【问题标题】:django admin inline many to many custom fieldsdjango admin 内联多对多自定义字段
【发布时间】:2013-11-17 10:26:09
【问题描述】:

您好,我正在尝试在 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' 指的是从 表格。

这怎么可能?

【问题讨论】:

  • model = Table.rows.through更改为model = Row
  • 不起作用行没有表的外键
  • 我遇到了完全相同的问题。我添加了一个赏金,希望能得到更多关注。
  • RowInline 类将其模型指定为 Table.rows.throughTable.rows 多对多关系的自动生成的中间模型),然后请求其 name 字段 - 但中间模型没有这样的字段,它只有两个外键:一个到Table(命名为from_)和一个到Row(命名为to)。 TabularInline(或实际上任何 *Inline 类)将无法满足您的需求;您可能需要实现自定义子类。
  • 我在这里提出了一个更符合我正在做的事情的更新问题:stackoverflow.com/questions/21562645/…

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


【解决方案1】:
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',)

【讨论】:

  • 这似乎是个好主意,但它不适合我。我什至让函数返回简单的“测试”以排除实例的问题,但它似乎仍然无法找到该字段。
  • 你能发布一个堆栈跟踪吗?
  • 这是显示字段值的好方法。 readonly_fields 仅显示为标签,而不是 form field。所以django可以获取值并显示出来。但是您不能使用这种方法通过内联插入或更新数据。
  • 编辑了fieldsreadonly_fields 的答案,这对我使用最近的 django 有用。
  • 正是我想要的。通过只显示只读字段,我们可以防止在 中加载整个表格
【解决方案2】:

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

admin.py:

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

如上所述,RowInline 中的model 寻址您数据库中的下表,而不是您的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']

您不会看到任何错误或异常。因为您在RowInline 中的model 处理了一个中间表,并且该表确实具有这些字段。 Django 可以虚拟化虚拟表Table_Row 到这里并且可以处理这个。

但是我们可以在管理员中使用关系,使用__。如果您的代码确实有 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 无法评估它在其头顶设计的虚拟模型上的 __ 关系。

结论:

在你的Inlines 处理ManyToMany 关系中,你正在处理一个虚构的中介模型,你不能使用fieldsexclude 属性,因为你的 imaginary 模型没有这些字段,django 无法处理该 imaginary 表的关系。以下是可以接受的

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 工作人员可能会避免这种用法,因为它包含多个插入并且操作与更多表相关。

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

【讨论】:

    【解决方案3】:

    在你的 admin.py 中试试这个

        class RowInline(admin.TabularInline):
            model = Table.rows.through
            list_display = ('name',)
    
    
        class TableAdmin(admin.ModelAdmin):
            inlines = [
                RowInline,
                ]
            readonly_fields = ('rows',)
    

    【讨论】:

    • 这解决了我在管理工具中不想显示原始表格而只显示直通关系的问题。谢谢!
    猜你喜欢
    • 2011-02-23
    • 2010-12-20
    • 2016-02-23
    • 1970-01-01
    • 2018-02-22
    • 2018-10-11
    • 2013-03-17
    • 2016-03-21
    • 2012-06-09
    相关资源
    最近更新 更多