ContentType в Django

Управление контентом в Django: создание гибкой системы баннеров

Django предоставляет приложение contenttypes, которое позволяет отслеживать все модели, установленные в вашем проекте, и обеспечивает высокоуровневый, общий интерфейс для работы с вашими моделями.

Основные принципы

В основе приложения contenttypes лежит модель ContentType, которая представляет собой информацию о моделях, установленных в вашем проекте. Экземпляры ContentType автоматически создаются каждый раз, когда создаются новые модели.

Что такое ContentType?

ContentType является экземпляром модели ContentType, которая хранит информацию о типе содержимого. Это включает в себя:

  • app_label: название приложения, к которому принадлежит тип содержимого
  • model: название модели, к которой принадлежит тип содержимого

Для чего нужен ContentType?

ContentType нужен для нескольких целей:

  1. Управление содержимымContentType позволяет управлять содержимым в базе данных, определяя тип данных, которые хранятся в каждой таблице.
  2. Связь между моделямиContentType позволяет связывать модели между собой, определяя тип содержимого, которое они представляют.
  3. Динамическое создание моделейContentType позволяет создавать модели динамически, без необходимости определять их заранее.
  4. Generic foreign keysContentType позволяет использовать generic foreign keys, которые могут ссылаться на любую модель в базе данных.

Пример использования ContentType

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

Код

from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.db.models import When, Case, Q
from django.utils.translation import gettext_lazy as _


class ContentTypeProxy(ContentType):
    """Для сортировки баннеров по приоритету"""
    
    class Meta:
        proxy = True
        ordering = [
            Case(
                When(model='bannerhorizontal', then=1),
                When(app_label='events', model='event', then=2),
                When(app_label='clubs', model='club', then=3),
                When(app_label='styles', model='style', then=4),
                When(app_label='musicians', model='musician', then=5),
                When(app_label='photoblogs', model='photoblog', then=6),
                When(app_label='albums', model='album', then=7),
                When(app_label='festivals', model='festival', then=8),
                When(app_label='instruments', model='instrument', then=9),
                When(app_label='learnings', model='learning', then=10),
                default=11
            )
        ]

    def __str__(self):
        """Для вывода нужных названий баннеров в админке"""
        if self.app_label == "general" and self.model == "bannerhorizontal":
            return str(_("Main"))
        if self.app_label == "events" and self.model == "event":
            return str(_("Poster"))
        if self.app_label == "clubs" and self.model == "club":
            return str(_("Clubs"))
        if self.app_label == "styles" and self.model == "style":
            return str(_("Styles"))
        if self.app_label == "musicians" and self.model == "musician":
            return str(_("People"))
        if self.app_label == "photoblogs" and self.model == "photoblog":
            return str(_("Photo blog"))
        if self.app_label == "albums" and self.model == "album":
            return str(_("Albums"))
        if self.app_label == "festivals" and self.model == "festival":
            return str(_("Festivals"))
        if self.app_label == "instruments" and self.model == "instrument":
            return str(_("Instruments"))
        if self.app_label == "learnings" and self.model == "learning":
            return str(_("Learnings"))
        return "super().__str__()"


class BannerHorizontal(models.Model):
    """Banner"""
    
    ADVERT_APPS = (
            Q(app_label="general", model="bannerhorizontal")
            | Q(app_label="events", model="event")
            | Q(app_label="clubs", model="club")
            | Q(app_label="styles", model="style")
            | Q(app_label="musicians", model="musician")
            | Q(app_label="photoblogs", model="photoblog")
            | Q(app_label="albums", model="album")
            | Q(app_label="festivals", model="festival")
            | Q(app_label="instruments", model="instrument")
            | Q(app_label="learnings", model="learning")
    )

    name = models.CharField(_("Name"), max_length=50)
    under_name = models.CharField(_("Under name"), max_length=50, blank=True)
    logo = models.FileField(_("Logo"), upload_to="banners/")
    link = models.URLField(_("Link"), blank=True, null=True)
    content_type = models.ManyToManyField(
        ContentTypeProxy,
        verbose_name=_("Show on pages"),
        limit_choices_to=ADVERT_APPS,
        related_name="banners",
    )
    published = models.BooleanField(_("Published"), default=False)
    sort = models.IntegerField(_("Sort"), default=0)

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = _("Banner horizontal")
        verbose_name_plural = _("Banners horizontal")
        ordering = ("sort",)

Этот код представляет собой часть Django-приложения, которое управляет баннерами на сайте. Баннеры могут быть показаны на различных страницах сайта, и этот код позволяет управлять этими баннерами и их местоположением.

ContentTypeProxy

Первый класс, ContentTypeProxy, является прокси-моделью для ContentType из Django. ContentType - это модель, которая хранит информацию о всех моделях в проекте. Прокси-модель позволяет нам добавить дополнительную логику к ContentType без изменения исходного кода Django.

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

Мы также добавляем поле ordering, которое определяет порядок, в котором будут показаны ContentType в админке. В этом случае мы используем Case и When из Django, чтобы определить порядок на основе имени модели и приложения.

BannerHorizontal

Второй класс, BannerHorizontal, представляет собой модель баннера. Баннер имеет следующие поля:

  • name: название баннера
  • under_name: подзаголовок баннера
  • logo: логотип баннера
  • link: ссылка на баннер
  • content_type: поле ManyToMany, которое связывает баннер с ContentTypeProxy. Это позволяет нам показывать баннер на различных страницах сайта.
  • published: флаг, который показывает, опубликован ли баннер
  • sort: поле, которое определяет порядок показа баннеров

Мы также добавляем метод __str__, который возвращает название баннера.

ADVERT_APPS

Переменная ADVERT_APPS представляет собой кортеж Q-объектов, которые определяют приложения и модели, которые могут быть связаны с баннером. Это позволяет нам ограничить выбор ContentType в админке Django.

Использование

Этот код можно использовать в админке Django для управления баннерами и их местоположением. Например, мы можем создать баннер и выбрать страницы, на которых он будет показан, используя поле content_type. Мы также можем изменить порядок показа баннеров, используя поле sort.

В целом, этот код позволяет нам управлять баннерами на сайте и показывать их на различных страницах, используя ContentType из Django.