Подтвердить что ты не робот

Django admin встроил многие из многих настраиваемых полей

Привет, я пытаюсь настроить мои встроенные строки в admin django.

Вот мои модели:

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' относится к имени поля, которое отсутствует в форма.

Как это возможно?

4b9b3361

Ответ 1

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

Это представляет проблему, поскольку Table.rows.through представляет собой промежуточную модель. Если вы хотите это лучше понять, посмотрите на свою базу данных. Вы увидите промежуточную таблицу, которая ссылается на эту модель. Вероятно, это имя называется apname_table_rows. Эта промежуточная модель не содержит поля, имя. У этого есть только два поля внешнего ключа: таблица и строка. (И он имеет поле id.)

Если вам нужно имя, на него можно ссылаться как поле readonly через отношение строк.

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

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)

Итак, если вы отредактируете свою Inline как следующую

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! Поскольку в вашей модели нет таблицы real, и django не может оценивать отношения __ на виртуальных моделях, которые она создает поверх своей головы.

Вывод:

В ваших Inline адресных ManyToMany отношениях вы имеете дело с воображаемой посреднической моделью, и вы не можете использовать атрибуты fields или exclude, потому что ваша воображаемая модель не имеет этих полей, а django не может обрабатывать отношения над этой воображаемой таблицей. Следующее будет приемлемым

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

а django отобразит комбинированные поля для параметров вашей виртуальной промежуточной таблицы и добавит яркий зеленый знак + для добавления новых записей, но вы не сможете иметь встроенные поля для добавления новых записей непосредственно в свою базу данных на одной и той же странице, Djnago не может справиться с этим на одной странице.

Вы можете попробовать создать промежуточную таблицу real и показать ее с помощью через, но это полная работа, и я не проверяйте его, чтобы увидеть его результаты.

Обновление: Существует также причина, по которой 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',)