Hi I am trying to customize my inlines in django admin.
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/
'RowInline.fields' refers to field 'name' that is missing from the form.
How is that possible ?
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.)
If you need the name it can be referenced as a readonly field through the rows relation.
In your admin.py try this
Django can not display it as you expected. Because there is an intermediary join table which joins your tables. In your example:
admin.py:
As the above note,
model
inRowInline
addressing following table in your database, not YourRow
table and modelYou can think it like there is an imaginary table in your model that joins the two tables.
So if you edit your Inline as following
you will not see any error or exception. Because your
model
inRowInline
addresses an intermediary table and that table do have those fields. Django can virtualize the imaginary tableTable_Row
up to here and can handle this.But we can use relations in admin, with using
__
. If your code do have aForeignKey
relation instead ofManyToManyField
relation, then following be valid in your adminand your admin:
Because you will have real Models and djnago can evaluate
__
relation on themBut if you try that in your structure:
and your admin:
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.Conclusion:
In your
Inline
s addressingManyToMany
relations, you are dealing with an imaginary intermediary model and you can not usefields
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 acceptableand 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.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:
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.But this is just an assumption on the reason of the behavior.