Ограничение типов контента в модели Django
В этой статье мы рассмотрим, как ограничить типы контента при работе с общими отношениями в Django:
- Как ограничить типы контента в модели Django?
- Как ограничить общий
ForeignKey
Django списком моделей?
Содержимое
Введение
Встроенный в Django фреймворк типов контента позволяет отслеживать все модели, установленные в вашем проекте. По своей сути, платформа предоставляет модель ContentType и автоматически создает экземпляр ContentType
для каждой из установленных вами моделей.
Эти экземпляры ContentType
хранят информацию о вашей модели и предоставляют методы для получения экземпляров соответствующих моделей - например, get_object_for_this_type().
Кроме того, фреймворк позволяет вам реализовывать "общие" отношения, которые представляют собой отношения между экземпляром одной из ваших моделей и любой другой моделью. Например, используя общие связи, вы можете создать единую систему тегов или комментариев, которая будет работать во всех ваших моделях.
Однако, в большинстве унифицированных систем вы, как правило, захотите ограничить их подмножеством своих моделей. В этой статье рассматривается именно это.
Ограничить типы контента
Предположим, мы работаем над веб-приложением для автосалона. Дилерский центр продает три типа транспортных средств: легковые автомобили, электромобили и мотоциклы. В результате у нас есть три модели Django для транспортных средств и еще одна для отслеживания продаж автомобилей.
Модели выглядят примерно так:
class Car(models.Model):
# ...
class ElectricCar(models.Model):
# ...
class Motorcycle(models.Model):
# ...
class Sale(models.Model):
content_type = models.ForeignKey(
ContentType,
on_delete=models.CASCADE,
)
object_id = models.PositiveIntegerField()
# ...
Хотя это позволяет нам связать продажу с экземпляром транспортного средства через content_type
и object_id
, это не идеально. Не ограничивая типы контента, пользователь технически может также связать продажу с моделью, не относящейся к автомобилю, например, auth.user
.
Давайте исправим это.
Во-первых, определите список вариантов выбора типа контента следующим образом:
from django.db.models import Q
from dealership.apps import DealershipConfig
CONTENT_TYPE_CHOICES = (
Q(app_label=DealershipConfig.name, model=Car.__name__.lower())
| Q(app_label=DealershipConfig.name, model=ElectricCar.__name__.lower())
| Q(app_label=DealershipConfig.name, model=Motorcycle.__name__.lower())
)
Кроме того, вы можете жестко задать ярлыки приложений и названия моделей. Это полезно при работе со сторонними приложениями, где у вас нет прямого доступа к конфигурации приложения. Например:
Q(app_label="dealership", model="car")
Имейте в виду, что название приложения и модели всегда должно быть в нижнем регистре. Например, если ваша модель называется FooBarFaz,
, название модели должно быть foobarfaz
.
Если вы не уверены в названиях приложений или моделей, вы можете перечислить все зарегистрированные типы контента, используя оболочку Django:
from django.contrib.contenttypes.models import ContentType for content_type in ContentType.objects.all(): print(content_type.app_label, content_type.model)
Затем установите параметр Foreign keys limit_choices_to в только что определенный список:
class Sale(models.Model):
content_type = models.ForeignKey(
ContentType,
on_delete=models.CASCADE,
limit_choices_to=CONTENT_TYPE_CHOICES,
)
# ...
Вносите изменения, мигрируйте и тестируйте.
Типы контента теперь ограничены значениями Car
, ElectricCar
, и Motorcycle
. Более того, на панели администратора будет отображаться только ограниченное количество типов контента.
Заключение
Итак, мы рассмотрели, как ограничить типы контента в модели Django.
Самый простой способ ограничить типы контента - это использовать параметр ForeignKey
из limit_choices_to
. При указании подмножества типов контента вы можете использовать -
- Конфигурация приложения
- Конфигурация модели
Или вы можете жестко задать значения. Если вы решите использовать жесткий код, укажите название приложения и модели в нижнем регистре.
Полный пример доступен на GitHub..
Вернуться на верх