Абстрактные модели в Django. Что это и когда их использовать?
При написании моделей для нашего проекта, зачастую приходится писать очень много дублирующихся полей, или полей, крайне схожих друг с другом, которые можно привести к одному виду. Чтобы не писать каждый раз одинаковые поля, и следовать принципу DRY, придумали абстрактные модели (Django Abstract models).
Проблема:
Возьмем простой и понятный пример. Допустим у нас есть модель Post (статьи) и Category (категории). И у каждой модели должы быть схожие поля created_at (дата создания), is_active (опубликовано или нет), и давайте возьмем еще title.
В обычном случае, мы бы написали наш модели следующим образом:
class Post(models.Model):
""" Model for storing Post objects """
class Meta:
verbose_name = 'Статья'
verbose_name_plural = 'Статьи'
title = models.CharField(max_length=120, verbose_name='Заголовок')
is_active = models.BooleanField(default=True, verbose_name='Опубликовано')
created_at = models.DateTimeField(
auto_now=True, verbose_name='Дата создания'
)
cover = models.ImageField(upload_to='bla_bla_bla/', verbose_name='Обложка')
body = models.TextField(verbose_name='Текст статьи')
def __str__(self):
return self.title
class Category(models.Model):
""" Model for storing Category objects """
class Meta:
verbose_name = 'Категория'
verbose_name_plural = 'Категории'
title = models.CharField(max_length=120, verbose_name='Заголовок')
is_active = models.BooleanField(default=True, verbose_name='Опубликовано')
created_at = models.DateTimeField(
auto_now=True, verbose_name='Дата создания'
)
parent = models.ForeignKey(
to='self', blank=True, null=True,
on_delete=models.CASCADE, verbose_name='Родительская категория'
)
def __str__(self):
return self.title
Согласитесь, выглядит не очень? Одинаковые поля мы прописали в двух моделях, а иногда и в большем количестве моделей.
Решение:
Решение очень простое, использовать Abstract models. Abstract models - это что-то наподобие миксинов для django моделей. Абстрактная модель не создает таблицу в базе данных при запуске миграций, но зато от неё можно наследоваться и расширять наши модели.
class CommonDataAbstractModel(models.Model):
"""
Abstract model for storing common data
"""
class Meta:
abstract = True
title = models.CharField(max_length=120, verbose_name='Заголовок')
is_active = models.BooleanField(default=True, verbose_name='Опубликовано')
created_at = models.DateTimeField(
auto_now=True, verbose_name='Дата создания'
)
class Post(CommonDataAbstractModel):
""" Model for storing Post objects """
class Meta:
verbose_name = 'Статья'
verbose_name_plural = 'Статьи'
cover = models.ImageField(upload_to='bla_bla_bla/', verbose_name='Обложка')
body = models.TextField(verbose_name='Текст статьи')
def __str__(self):
return self.title
class Category(CommonDataAbstractModel):
""" Model for storing Category objects """
class Meta:
verbose_name = 'Категория'
verbose_name_plural = 'Категории'
parent = models.ForeignKey(
to='self', blank=True, null=True,
on_delete=models.CASCADE, verbose_name='Родительская категория'
)
def __str__(self):
return self.title
Согласитесь удобно? - Особенно если у нас одинаковые поля не в двух моделях, а например в десятке.
Пометки:
-
Крайне удобно выносить в абстрактные модели поля для SEO функционала.
-
Рекомендую хранить абстрактные модели отдельно, в каком-нибудь основном приложении например в файле mixins.py.
Оставить комментарий