Страницы

Поиск по вопросам

среда, 15 мая 2019 г.

Связать в одном поле 2 модели?

У меня есть 3 модели: class category(models.Model): title = models.CharField(max_length=255, verbose_name='название')
class page(models.Model): title = models.CharField(max_length=255, verbose_name='заголовок') text = models.TextField(verbose_name='текст')
class menu(models.Model): title = models.CharField(max_length=255, verbose_name='заголовок') content = models.ForeignKey(Page or Category) # <- How to? link = models.CharField(max_length=255) Как сделать, что бы menu.content ссылалась либо на страницу, либо на категорию, и в зависимости от того, на что она ссылается в menu.link должно быть либо category/, либо page/?


Ответ

Можно через generic relations, как-то так: content_type = models.ForeignKey(ContentType) object_id = models.IntegerField() content_object = generic.GenericForeignKey('content_type', 'object_id') Но, вроде бы, нет толкового метода ограничить на что может ссылаться GFK, разве что в БД пост-фактум (уже после заполнения таблицы content_types) засунуть констрейнты по ID, чтобы подстраховаться. Другой вариант — через multi-table inheritance class MenuItem(models.Model): title = ... link = ...
class Page(MenuItem): text = ...
... Но, опять же, некрасиво — MenuItem.objects вернет объекты класса MenuItem, а не Page. Т.е. придется выбирать отдельно по каждой таблице и склеивать. Третий вариант — если СУБД умеет наследование (как, скажем, PostgreSQL), то использовать его и raw SQL. CREATE TABLE menu_items ( ... ); CREATE TABLE pages ( ...) INHERITS (menu_items); Тогда SELECT * FROM menu_items может использовать все поля из таблиц-наследников. Но, опять же, это некрасиво — ломимся мимо Django'вского ORM'а. Хотя можно выкрутиться через unmanaged models и, возможно, представления для SELECT ... FROM ONLY ... (если они нужны; т.к. ORM никогда сам запрос не родит). Четвертый вариант — завести два ForeignKey, page и category, и влепить констрейнт, что одно и только одно из них должно быть NULL (None). И сделать, для удобства, @property у модели, которое вернет то, что is not None. По мне так лучший из вариантов, но совершенно не подходит для ситуаций, когда типов объектов много.

Комментариев нет:

Отправить комментарий