Django Admin嵌套内联中外键数据保存异常问题求助
问题分析与解决方案
核心错误原因
django-nested-admin的sortable_field_name需要指向一个专门用于存储排序顺序的整数字段,你当前把它设置成了内容字段(如img、text、caption)。系统保存排序时会将位置数值写入该字段,导致文本字段被强制转为整数0,图片字段因无法转换抛出AttributeError。
此外还有两处次要问题:
Multimg的get_image_filename是实例方法,不能直接用于upload_to,且引用了不存在的instance.postDelta模型中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
相关产品推荐
相关产品推荐

