<- Просто о Django Content Types Framework
Появилась задача реализовать функцию комментариев для пяти моделей через одну. Небольшой пример, как это могло выглядеть без Content Types Framework:
class Comment(models.Model):
user = models.ForeignKey('User', related_name='comment')
title = models.CharField(max_length=255)
body = models.TextField()
article = models.ForeignKey('Article', related_name='comment')
todo = models.ForeignKey('ToDo', related_name='comment')
blog_post = models.ForeignKey('BlogPost', related_name='comment')
image = models.ForeignKey('Image', related_name='comment')
album = models.ForeignKey('Album', related_name='comment')
Пример с Content Types:
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
class Comment(models.Model):
user = models.ForeignKey('User', related_name='comment')
title = models.CharField(max_length=255)
body = models.TextField()
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
Куда более компактный код, не так ли? И так, что же такое Content Types Framework и как он работает?
Content Types Framework сохраняет информацию о моделях в таблицу contenttypes, а именно: название приложения, название модели и тип.
Таким образом мы можем создать GenericForeignKey на любую модель используя всего одно поле.
Получить объект Content Type можно двумя способами:
по классу нашей модели
ContentType.objects.get_for_model(Article)
или по названию модели
from django.contrib.contenttypes.models import ContentType
article_type = ContentType.objects.get(app_label='core', model='article')
теперь можно получить модель через Content Type Object:
model = user_type.model_class()
Это бывает очень удобно, например, если мы хотим получить список статей, картинок, альбомов через шаблон из URL используя только одно представление:
class MyTypes(View):
def get(self, request, *args, **kwargs):
content_type_name = kwargs.get('name')
# Получаем content type по названию модели из url
content_type = get_object_or_404(ContentType, name=content_type_name)
# Получаем модель
model = content_type.get_for_model()
context = {
'objects': model.objects.all()
}
Так можно получить список комментариев определенной статьи
first_article = Article.objects.get(pk=1)
content_type = ContentType.objects.get_for_model(first_article)
object_list = Comment.objects.filter(
content_type__pk=content_type.pk,
object_id=first_article.pk
)