16

嗨,我正在尝试在 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”指的是表单中缺少的字段“名称”。

这怎么可能?

4

3 回答 3

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

这带来了一个问题,因为 Table.rows.through 代表一个中间模型。如果您想更好地理解这一点,请查看您的数据库。您将看到一个引用此模型的中间表。它可能被命名为 apname_table_rows。此中间模型不包含字段名称。它只有两个外键字段:表和行。(并且它有一个 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',)
于 2014-02-05T07:12:45.447 回答
7

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

管理员.py:

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

如上所述,modelRowInline处理数据库中的下表时,而不是您的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']

您不会看到任何错误或异常。因为您的modelinRowInline地址是一个中间表,而该表确实有这些字段。Django 可以将虚拟表虚拟化Table_Row到这里并且可以处理这个。

但是我们可以在 admin 中使用关系,使用 using __。如果您的代码确实有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记录以加入这两个。所以 in 包含多个数据库插入。Django 工作人员可能会避免这种用法,因为它包含多个插入并且操作与更多表相关。

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

于 2014-02-05T12:31:11.260 回答
1

在你的 admin.py 试试这个

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


    class TableAdmin(admin.ModelAdmin):
        inlines = [
            RowInline,
            ]
        readonly_fields = ('rows',)
于 2014-02-05T10:29:06.677 回答