You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django Admin嵌套内联中外键数据保存异常问题求助

问题分析与解决方案

核心错误原因

django-nested-admin的sortable_field_name需要指向一个专门用于存储排序顺序的整数字段,你当前把它设置成了内容字段(如img、text、caption)。系统保存排序时会将位置数值写入该字段,导致文本字段被强制转为整数0,图片字段因无法转换抛出AttributeError。

此外还有两处次要问题:

  • Multimg的get_image_filename是实例方法,不能直接用于upload_to,且引用了不存在的instance.post
  • Delta模型中null="true"是字符串,应为布尔值True

步骤1:给所有需要排序的模型添加排序字段

修改models.py,为每个需要排序的模型添加order整数字段:

from django.utils.text import slugify
from django.urls import reverse
from django.utils import timezone
from django.db import models
from django.contrib.auth.models import User
import tinymce.models

class Multis(models.Model):
    name = models.TextField(max_length=50, null=True, blank=True)
    delta = models.ForeignKey('Delta', related_name="delta", null=True, on_delete=models.CASCADE)
    # 添加排序字段
    order = models.IntegerField(default=0, db_index=True)

    class Meta:
        # 改为按order字段排序
        ordering = ('order',)

    def __str__(self):
        return str(self.name)

class Multicap(models.Model):
    caption = models.TextField(max_length=50, null=True, blank=True)
    multic = models.ForeignKey('Multis', related_name="multicap", null=True, on_delete=models.CASCADE)
    # 添加排序字段
    order = models.IntegerField(default=0, db_index=True)

    class Meta:
        ordering = ('order',)

    def __str__(self):
        return str(self.caption)


class Multimg(models.Model):
    img = models.ImageField(upload_to="images", verbose_name='Image', null=True, blank=True,)
    multim = models.ForeignKey('Multis', related_name="multimg", null=True, on_delete=models.CASCADE)
    # 添加排序字段
    order = models.IntegerField(default=0, db_index=True)

    class Meta:
        ordering = ('order',)

    @property
    def img_url(self):
      if self.img and hasattr(self.img, 'url'):
        return self.img.url

    # 修正upload_to方法:改为静态方法,且引用正确的关联对象
    @staticmethod
    def get_image_filename(instance, filename):
        # 关联的是Multis,所以取instance.multim.name
        title = instance.multim.name if instance.multim.name else "unnamed"
        slug = slugify(title)
        return "post_images/%s-%s" % (slug, filename)

    def get_absolute_url(self):
        return reverse('delta-detail', kwargs={'pk': self.pk})


class Multitext(models.Model):
    text = tinymce_models.HTMLField(null=True, blank=True)
    multit = models.ForeignKey('Multis', related_name="multitext", null=True, on_delete=models.CASCADE)
    # 添加排序字段
    order = models.IntegerField(default=0, db_index=True)

    class Meta:
        ordering = ('order',)

    def __str__(self):
        return str(self.text)[:50]  # 截断过长的文本,避免admin显示问题

class Delta(models.Model):
    heading = models.CharField(max_length=50, null=True)  # 修正null="true"为null=True
    date_posted = models.DateTimeField(default=timezone.now)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    # 添加排序字段(如果需要对Delta实例排序)
    order = models.IntegerField(default=0, db_index=True)

    class Meta:
        ordering = ('order',)

    def __str__(self):
        return str(self.heading)

    def get_absolute_url(self):
        return reverse('delta-detail', kwargs={'pk': self.pk})

步骤2:修改admin配置,指向正确的排序字段

修改admin.py,将所有sortable_field_name改为对应的order字段:

from django.contrib import admin
import nested_admin
from nested_admin import SortableHiddenMixin, NestedStackedInline, NestedModelAdmin
from .models import Delta, Multimg, Multitext, Multicap, Multis


class MimgAdmin(nested_admin.NestedStackedInline):
    model = Multimg
    sortable_field_name = "order"  # 改为排序字段
    extra = 0

class MtxtAdmin(nested_admin.NestedStackedInline):
    model = Multitext
    sortable_field_name = "order"  # 改为排序字段
    extra = 0

class McapAdmin(nested_admin.NestedStackedInline):
    model = Multicap
    sortable_field_name = "order"  # 改为排序字段
    extra = 0

class MAdmin(nested_admin.SortableHiddenMixin, nested_admin.NestedStackedInline):
    model = Multis
    sortable_field_name = "order"  # 改为排序字段
    extra = 0
    inlines = [ McapAdmin, MtxtAdmin, MimgAdmin ]


@admin.register(Delta)
class DeltaAdmin(nested_admin.NestedModelAdmin):
    sortable_field_name = "order"  # 改为排序字段
    inlines = [ MAdmin ]

步骤3:数据库迁移

执行以下命令更新数据库结构:

python manage.py makemigrations
python manage.py migrate

额外说明

  • SortableHiddenMixin会自动隐藏order字段的输入框,仅通过拖拽调整顺序
  • 若不需要对Delta实例本身排序,可以移除Delta模型的order字段和DeltaAdmin中的sortable_field_name
  • Multitext的__str__方法做了截断处理,避免过长的HTML文本导致admin显示异常

内容的提问来源于stack exchange,提问作者Lorenzo Scodeller

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 04:01:07