django admin内联多个自定义字段

时间:2013-11-06 09:03:45

标签: python django django-forms django-admin django-1.5

您好我正在尝试在django admin中自定义我的内联。

以下是我的模特:

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

和我的管理员:

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


class TableAdmin(admin.ModelAdmin):
    inlines = [
        RowInline,
    ]
    exclude = ('rows',)

但是我收到此错误

  

在/ admin / table_app / table / 1 /

处配置不当      

'RowInline.fields'指的是缺少的字段'name'   形式。

怎么可能?

3 个答案:

答案 0 :(得分:19)

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

这提出了一个问题,因为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',)

答案 1 :(得分:8)

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

admin.py:

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

如上所述,model RowInline代表数据库中的下表,而非Row表和模型

table: your-app-name_table_row
--------------------------------
id       | int not null
table_id | int
row_id   | int

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

class Table_Row(Model):
    table = ForeignKey(Table)
    row = ForeignKey(Row)

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

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

您不会看到任何错误或异常。因为model中的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

和您的管理员:

class RowInline(admin.TabularInline):
    model = Table
    fields = ['rows__name']

因为您将拥有真实的模型,而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

和您的管理员:

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

它将raise Exception!因为您的模型中没有真实表,并且django无法评估虚拟模型上的__关系,所以它设计在它的顶端。

结论:

Inline寻址ManyToMany关系中,您正在处理虚构的中间模型,而您无法使用fieldsexclude因为你的虚构的模型没有那些字段而且django无法处理虚构表的关系。以下是可以接受的

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

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

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

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

          Table   | Table_Row |   Row
       -----------+-----------+---------
Start      5      |           |          
Step 1     5      |           |    1
Step 2     5      |    5-1    |    1  

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

但这只是对行为原因的假设。

答案 2 :(得分:1)

在你的admin.py中试试这个

    class RowInline(admin.TabularInline):
        model = Table.rows.through
        list_display = ('name',)


    class TableAdmin(admin.ModelAdmin):
        inlines = [
            RowInline,
            ]
        readonly_fields = ('rows',)