Django - Проектирование модельных отношений - Интерфейс администратора и Inline - PullRequest
1 голос
/ 17 декабря 2009

Я думаю, что мое понимание FK и администратора Django немного ошибочно, поэтому я бы оценил любой вклад в то, как смоделировать приведенный ниже случай.

Во-первых, у нас есть общие объекты Address. Затем у нас есть User, у каждого из которых есть UserProfile. Благодаря этому Пользователи принадлежат к отделам, а также имеют адреса.

У самих отделов также может быть несколько адресов, как и у начальника отдела. Так что это может быть что-то вроде (это то, что я сейчас просто взломал):

class Address(models.Model):
    street_address = models.CharField(max_length=20)
    etc...

class Department(models.Model):
    name = models.CharField(max_lenght=20)
    head_of_department = models.OneToOneField(User)
    address = models.ForeignKey(Address)

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)
    address = models.ForeignKey(Address)
    department = models.OneToOneField(Department)

Так или иначе, во-первых, это правильный способ установить отношения?

И во-вторых, я хотел бы, чтобы в админе появилось сообщение о том, что вы можете редактировать отдел, и на этой странице будет встроенный список всех адресов, которые также можно редактировать. Я попытался настроить класс AddressInline и прикрепить его как встроенный к Department.

class AddressInline(admin.TabularInline):
    model = Address

class DepartmentAdmin(admin.ModelAdmin):
    inlines = [AddressInline]

Однако, когда я пытаюсь отобразить это, я получаю:

Exception at /admin/people/department/1/
<class 'people.models.Address'> has no ForeignKey to <class 'people.models.Department'>

Cheers, Victor

Ответы [ 2 ]

2 голосов
/ 17 декабря 2009

Поскольку кажется, что вы хотите, чтобы UserProfile или Department имели потенциально много адресов, ваши ForeignKeys являются обратными. Один ForeignKey может указывать только на один экземпляр модели, в то время как не существует ограничения на количество ForeignKeys, которые могут указывать на один экземпляр модели. Таким образом, ваш ForeignKey должен быть указан по адресу (в этом случае встроенный код будет работать как есть).

Осложняющим фактором является то, что у вас есть модель с одним адресом, и вы хотите связать ее с двумя другими моделями; один ключ ForeignKey on Address не может указывать как на UserProfile, так и на Department. Одно из решений состоит в том, чтобы иметь две модели адресов (DepartmentAddress, с ForeignKey to Department, и UserAddress, с ForeignKey to UserProfile). Вы можете уменьшить дублирование в своем коде, если они оба наследуются от абстрактного базового класса , содержащего все поля данных, но у вас все равно останутся две практически идентичные таблицы в вашей базе данных.

Другой вариант - иметь GenericForeignKey для адреса, который может указывать на экземпляр любой модели. В таком случае ваш встроенный код должен стать GenericInlineModelAdmin . Это нарушает обычную нормализацию базы данных и не позволяет вашей базе данных выполнять надлежащую проверку целостности. Если бы в будущем у вас было потенциально больше моделей, у которых также были бы адреса, я бы обдумал это; если он может быть ограничен только двумя текущими, я мог бы использовать вышеупомянутую опцию.

0 голосов
/ 17 декабря 2009

Я читаю ваши модели что вы хотите от своих моделей как:

A department has one to many addresses

A department has one and only one user (as head of department)

A user (through his profile) belongs to one to many departments

A user (through his profile) has one to many addresses

Если это было вашим намерением, это означает, что нет случая, когда у пользователя НЕ будет адреса или отдела, и нет случая, когда у отдела не будет адреса или начальника отдела; тогда я бы сказал, что ваши модели в порядке должны читать:

class Department(models.Model):
    name = models.CharField(max_lenght=20)
    head_of_department = models.OneToOneField(User)
    address = models.ForeignKey(Address)

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)
    address = models.ForeignKey(Address)
    department = models.OneToOneField(Department)

class Address(models.Model):
    street_address = models.CharField(max_length=20)
    ...

    class Meta:
        abstract = True

class UserAddress(Address):
    user_profile = models.ForeignKey(UserProfile)

class DepartmentAddress(Address):
    department = models.ForeignKey(Department)

Подробнее о абстрактных классах .

Ваши модели не рассматривают возможности того, что два пользователя будут иметь один и тот же адрес и / или два отдела будут иметь один и тот же адрес. Поскольку вы не указываете уникальное ограничение на адрес (которое я вижу), я предполагаю, что вы в порядке с реальным адресом, который несколько раз отображается в таблице адресов.

Если с тобой все в порядке; хорошо.

Сообщение об ошибке, которое вы получаете, констатирует факт: в Address to Department отсутствует внешний ключ. Вы должны будете вернуть эти отношения, чтобы встроенные функции работали. Это означает, что при редактировании адреса вы можете редактировать любые отделы, связанные с ним; но не наоборот. С моделями, которые я предлагаю выше, вы не должны видеть эту ошибку.

См. Пример из документов . Обратите внимание на то, как Author has many Books и как много сторон отношений могут быть встроенными.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...