У меня есть 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/
Ответ
Можно через 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. По мне так лучший из вариантов, но совершенно не подходит для ситуаций, когда типов объектов много.
Комментариев нет:
Отправить комментарий