django admin内联多个自定义字段

maa*_*zza 12 python django django-forms django-admin django-1.5

嗨,我想在django管理员中自定义我的内联.

这是我的模特:

class Row(models.Model):
    name = models.CharField(max_length=255)

class Table(models.Model):
    rows = models.ManyToManyField(Row, blank=True)
    name = models.CharField(max_length=255)

    def __unicode__(self):
        return self.name
Run Code Online (Sandbox Code Playgroud)

和我的管理员:

class RowInline(admin.TabularInline):
    model = Table.rows.through
    fields = ['name']


class TableAdmin(admin.ModelAdmin):
    inlines = [
        RowInline,
    ]
    exclude = ('rows',)
Run Code Online (Sandbox Code Playgroud)

但是我得到了这个错误

在/ admin/table_app/table/1 /中配置不正确

'RowInline.fields'指的是表单中缺少的字段'name'.

怎么可能?

sj7*_*sj7 19

class RowInline(admin.TabularInline):
    model = Table.rows.through
    fields = ['name']
Run Code Online (Sandbox Code Playgroud)

这提出了一个问题,因为Table.rows.through代表一个中间模型.如果您想了解这一点,请查看您的数据库.您将看到一个引用此模型的中间表.它可能被命名为apname_table_rows.此中介模型不包含字段名称.它只有两个外键字段:table和row.(它有一个id字段.)

如果需要名称,可以通过行关系将其引用为只读字段.

class RowInline(admin.TabularInline):
    model = Table.rows.through
    fields = ['row_name']
    readonly_fields = ['row_name']

    def row_name(self, instance):
        return instance.row.name
    row_name.short_description = 'row name'


class TableAdmin(admin.ModelAdmin):
    inlines = [
        RowInline,
    ]
    exclude = ('rows',)
Run Code Online (Sandbox Code Playgroud)

  • 这是“仅”显示字段值的好方法。“readonly_fields”仅显示为标签,而不显示为“表单字段”。这样django就可以获取该值并显示出来。但您不能使用这种方法通过内联插入或更新数据。 (2认同)

Fal*_*gel 8

Django无法按预期显示它.因为有一个连接表中间连接表.在你的例子中:

admin.py:

class RowInline(admin.TabularInline):
    model = Table.rows.through  # You are not addressing directly Row table but intermediary table
    fields = ['name']
Run Code Online (Sandbox Code Playgroud)

如上所述,modelRowInline数据库中寻址下表时,不是您的Row表和模型

table: your-app-name_table_row
--------------------------------
id       | int not null
table_id | int
row_id   | int
Run Code Online (Sandbox Code Playgroud)

您可以认为模型中有一个虚构的表连接两个表.

class Table_Row(Model):
    table = ForeignKey(Table)
    row = ForeignKey(Row)
Run Code Online (Sandbox Code Playgroud)

因此,如果您按照以下方式编辑内联

class RowInline(admin.TabularInline):
    model = Table.rows.through  # You are not addressing directly Row table but intermediary table
    fields = ['row', 'table']
Run Code Online (Sandbox Code Playgroud)

你不会看到任何错误或异常.因为你的modelin RowInline地址是一个中间表,那个表确实有这些字段.Django可以将虚构表虚拟Table_Row到这里并且可以处理这个问题.

但是我们可以在admin中使用关系,使用__.如果您的代码确实有ForeignKey关系而不是ManyToManyField关系,那么以下内容在您的管理员中有效

 class Row(models.Model):
    name = models.CharField(max_length=255)

class Table(models.Model):
    rows = models.ForeignKey(Row, blank=True)
    name = models.CharField(max_length=255)

    def __unicode__(self):
        return self.name
Run Code Online (Sandbox Code Playgroud)

和你的管理员:

class RowInline(admin.TabularInline):
    model = Table
    fields = ['rows__name']
Run Code Online (Sandbox Code Playgroud)

因为你将拥有真实的模型,而djnago可以评估__它们之间的关系

但是如果你在你的结构中尝试:

 class Row(models.Model):
    name = models.CharField(max_length=255)

class Table(models.Model):
    rows = models.ManyToManyField(Row, blank=True)
    name = models.CharField(max_length=255)

    def __unicode__(self):
        return self.name
Run Code Online (Sandbox Code Playgroud)

和你的管理员:

class RowInline(admin.TabularInline):
    model = Table.rows.through 
    fields = ['row__name']
Run Code Online (Sandbox Code Playgroud)

它会的raise Exception!因为你的模型中没有真正的表,并且django无法评估__虚拟模型上的关系,所以它设计在它的头顶.

结论:

在你Inline的寻址ManyToMany关系中,你正在处理一个虚构的中间模型,你不能使用fieldsexclude属性,因为你的想象模型没有那些字段,而django无法处理那个想象表的关系.以下是可以接受的

class RowInline(admin.TabularInline):
    model = Table.rows.through 
    # No fields or exclude declarations in here
Run Code Online (Sandbox Code Playgroud)

和django将显示虚拟中介表选项的组合框,并添加一个花哨的绿色+标志来添加新记录,但是您不能使用内联字段将新记录直接添加到同一单页中的数据库中.Djnago无法在单个页面上处理此问题.

您可以尝试创建真正的中间表并使用through来显示它,但这完全是一个更长的工作,我不测试它以查看其结果.

更新:还有一个原因,为什么django不会让这样的东西.考虑以下:

          Table   | Table_Row |   Row
       -----------+-----------+---------
Start      5      |           |          
Step 1     5      |           |    1
Step 2     5      |    5-1    |    1  
Run Code Online (Sandbox Code Playgroud)

一开始,你有一个没有相关行的表,你想在表中添加一行...要加入一个表的行,你必须先创建一行,这样你才能执行第1步.之后你创建了你的行行,你可以创建Table_Row记录来加入这两个.因此在包含多个数据库插入.Django工作人员可能会避免这种用法,因为它包含多个插入,操作与更多表相关.

但这仅仅是对行为原因的假设.