django管理内联到许多自定义字段

时间:2022-07-25 19:22:27

Hi I am trying to customize my inlines in django admin.

你好,我在django admin中定制我的inline。

Here are my models:

这是我的模型:

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

and my admin:

我的管理:

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


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

However I get this error

但是我得到了这个错误

ImproperlyConfigured at /admin/table_app/table/1/

在/ admin / ImproperlyConfigured table_app /表/ 1 /

'RowInline.fields' refers to field 'name' that is missing from the form.

“RowInline。字段'指的是表单中缺少的字段'name'。

How is that possible ?

这怎么可能呢?

3 个解决方案

#1


15  

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

This presents a problem because Table.rows.through represents an intermediate model. If you would like to understand this better have a look at your database. You'll see an intermediate table which references this model. It is probably named something like apname_table_rows. This intermeditate model does not contain the field, name. It just has two foreign key fields: table and row. (And it has an id field.)

这带来了一个问题,因为表。row。表示中间模型。如果您想了解这一点,请查看您的数据库。您将看到一个引用该模型的中间表。它可能被命名为类似apname_table_rows的东西。这个intermeditate模型不包含字段名。它只有两个外键字段:表和行。(它有一个id字段。)

If you need the name it can be referenced as a readonly field through the rows relation.

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

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',)

#2


7  

Django can not display it as you expected. Because there is an intermediary join table which joins your tables. In your example:

Django不能按预期显示它。因为中间有一个连接表的连接表。在你的例子:

admin.py:

admin.py:

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

As the above note, model in RowInline addressing following table in your database, not Your Row table and model

如上所述,在您的数据库中,RowInline寻址的模型,而不是您的行表和模型。

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

You can think it like there is an imaginary table in your model that joins the two tables.

您可以这样想,您的模型中有一个假想的表连接两个表。

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

So if you edit your Inline as following

如果你编辑你的内联如下

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

you will not see any error or exception. Because your model in RowInline addresses an intermediary table and that table do have those fields. Django can virtualize the imaginary table Table_Row up to here and can handle this.

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

But we can use relations in admin, with using __. If your code do have a ForeignKey relation instead of ManyToManyField relation, then following be valid in your 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

and your admin:

和你的管理:

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

Because you will have real Models and djnago can evaluate __ relation on them

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

But if you try that in your structure:

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

 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

and your admin:

和你的管理:

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

it will raise Exception! Because you do not have real table in your model, and django can not evaluate __ relations on virtual models it designs on top of its head.

它将提高异常!因为在您的模型中没有实际的表,django不能在它的顶部设计的虚拟模型上评估__关系。

Conclusion:

In your Inlines addressing ManyToMany relations, you are dealing with an imaginary intermediary model and you can not use fields orexclude attributes on that because your imaginary model do not have those fields and django can not handle relations ober that imaginary table. Following will be acceptable

在处理许多tomany关系的Inlines中,您处理的是一个虚构的中间模型,您不能在该模型上使用字段或排除属性,因为您的虚构模型没有这些字段,django不能处理虚构表的关系。下面将会被接受

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

and django will display combo boxes for your virtual intermediary table options and add a fancy green + sign to add new records, but you will can not have inline fields to add new records directly to your database within the same single page. Djnago can not handle this on a single page.

django将为您的虚拟中介表选项显示组合框,并添加一个漂亮的绿色+符号来添加新记录,但是您不能在同一个页面中使用内联字段直接向数据库添加新记录。Djnago不能在一个页面上处理这个。

You can try creating real intermediary table and show it using through, but thats totally a longer job and I do not test it to see its results.

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

Update: There is also the reason why django do not let something like that. Consider following:

更新:还有一个原因,django不会让这样的事情发生。考虑以下:

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

At the beginning, You have a table with no related Rows, you want to add a row to the table... For joining a row with a table, you must first create a row so you execute step 1. After You do create your row, you can create Table_Row record to join these two. So in contains more than a single database insertion. Django crew may avoid such usage since it contains multiple inserts and operation is related more tables.

首先,您有一个没有相关行的表,您想要向表添加一行……对于与表连接的行,必须首先创建一行,以便执行第1步。创建行之后,可以创建Table_Row记录来连接这两个。因此in包含不止一个数据库插入。Django crew可能会避免这种使用,因为它包含多个插入,并且操作涉及更多的表。

But this is just an assumption on the reason of the behavior.

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

#3


0  

In your admin.py try this

在你的管理。py试试这个

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


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

#1


15  

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

This presents a problem because Table.rows.through represents an intermediate model. If you would like to understand this better have a look at your database. You'll see an intermediate table which references this model. It is probably named something like apname_table_rows. This intermeditate model does not contain the field, name. It just has two foreign key fields: table and row. (And it has an id field.)

这带来了一个问题,因为表。row。表示中间模型。如果您想了解这一点,请查看您的数据库。您将看到一个引用该模型的中间表。它可能被命名为类似apname_table_rows的东西。这个intermeditate模型不包含字段名。它只有两个外键字段:表和行。(它有一个id字段。)

If you need the name it can be referenced as a readonly field through the rows relation.

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

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',)

#2


7  

Django can not display it as you expected. Because there is an intermediary join table which joins your tables. In your example:

Django不能按预期显示它。因为中间有一个连接表的连接表。在你的例子:

admin.py:

admin.py:

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

As the above note, model in RowInline addressing following table in your database, not Your Row table and model

如上所述,在您的数据库中,RowInline寻址的模型,而不是您的行表和模型。

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

You can think it like there is an imaginary table in your model that joins the two tables.

您可以这样想,您的模型中有一个假想的表连接两个表。

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

So if you edit your Inline as following

如果你编辑你的内联如下

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

you will not see any error or exception. Because your model in RowInline addresses an intermediary table and that table do have those fields. Django can virtualize the imaginary table Table_Row up to here and can handle this.

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

But we can use relations in admin, with using __. If your code do have a ForeignKey relation instead of ManyToManyField relation, then following be valid in your 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

and your admin:

和你的管理:

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

Because you will have real Models and djnago can evaluate __ relation on them

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

But if you try that in your structure:

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

 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

and your admin:

和你的管理:

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

it will raise Exception! Because you do not have real table in your model, and django can not evaluate __ relations on virtual models it designs on top of its head.

它将提高异常!因为在您的模型中没有实际的表,django不能在它的顶部设计的虚拟模型上评估__关系。

Conclusion:

In your Inlines addressing ManyToMany relations, you are dealing with an imaginary intermediary model and you can not use fields orexclude attributes on that because your imaginary model do not have those fields and django can not handle relations ober that imaginary table. Following will be acceptable

在处理许多tomany关系的Inlines中,您处理的是一个虚构的中间模型,您不能在该模型上使用字段或排除属性,因为您的虚构模型没有这些字段,django不能处理虚构表的关系。下面将会被接受

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

and django will display combo boxes for your virtual intermediary table options and add a fancy green + sign to add new records, but you will can not have inline fields to add new records directly to your database within the same single page. Djnago can not handle this on a single page.

django将为您的虚拟中介表选项显示组合框,并添加一个漂亮的绿色+符号来添加新记录,但是您不能在同一个页面中使用内联字段直接向数据库添加新记录。Djnago不能在一个页面上处理这个。

You can try creating real intermediary table and show it using through, but thats totally a longer job and I do not test it to see its results.

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

Update: There is also the reason why django do not let something like that. Consider following:

更新:还有一个原因,django不会让这样的事情发生。考虑以下:

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

At the beginning, You have a table with no related Rows, you want to add a row to the table... For joining a row with a table, you must first create a row so you execute step 1. After You do create your row, you can create Table_Row record to join these two. So in contains more than a single database insertion. Django crew may avoid such usage since it contains multiple inserts and operation is related more tables.

首先,您有一个没有相关行的表,您想要向表添加一行……对于与表连接的行,必须首先创建一行,以便执行第1步。创建行之后,可以创建Table_Row记录来连接这两个。因此in包含不止一个数据库插入。Django crew可能会避免这种使用,因为它包含多个插入,并且操作涉及更多的表。

But this is just an assumption on the reason of the behavior.

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

#3


0  

In your admin.py try this

在你的管理。py试试这个

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


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