Django Contenttypes
对于需要返回查询集的–写在
QuerySetModel
中
模型类中数据库处理的–写在
Models
中
业务相关逻辑的处理—写在
Views
中
记录Django项目中,所有模型类所属的应用,以及模型类的名字
- 对当前项目中所有给予Django驱动的model,提供了更高层次的抽象接口(models.Model,models.py)
- 方便我们
动态调用模型类
- Django权限管理中的Permission借助ContentType实现了对任意models的权限操作
GenericForeignKey
不支持使用on_delete
,默认就是删除级联
GenericRelation
- ContentType的通用类型–
GenericRelation
(实现对所有模型类的关联操作)
业务场景
- 多个模型类需要使用同一功能
- 如:博客、文章、图片、想法、笔记,每个模型类里面都需要使用评论功能
from django.contrib.auth.models import User
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.contenttypes.models import ContentType # 查看源码
from django.db import models
# 通用模型类
class Comment(models.Model):
author = models.ForeignKey(to=User, on_delete=models.CASCADE)
body = models.TextField(blank=True)
# 这三个字段组合起来 ==> 实现通用模型类(app_lable、model、id)
content_type = models.ForeignKey(ContentType, models.CASCADE)
object_id = models.IntegerField
content_object = GenericForeignKey()
# 再把这个模型类关联到其他的模型类中:
class Blog(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
body = models.TextField()
comments = GenericRelation(Comment) # 通用外检关联
class Article(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
body = models.TextField()
comments = GenericRelation(Comment) # 通用外检关联
class Picture(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
body = models.TextField()
comments = GenericRelation(Comment) # 通用外检关联
ContentType 的巧妙用法
Timeline设计
在首页展示不同模块的数据,按照时间排序
一般是使用个性推荐算法==> 不用用户在同一时间看到的数据是不一样的
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import models
# TODO: 信号量机制
from django.db.models.signals import post_save
class Index(models.Model):
"""首页--通用模型类"""
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey("content_type", "object_id")
pub_date = models.DateTimeField(auto_now_add=True)
class Meta:
"""
TODO
每当后面三个模型类中有数据生成的时候,都会在这里创建一条数据
最后在排序的时候,使用这里的数据进行排序,就能对不同模块的数据进行排序了
"""
ordering = ["-pub_date"]
# TODO:问题2:如何在调用基类的时候,获取到其他三张表中的数据
@property
def content(self):
return self.content_object.content
class News(models.Model):
"""动态"""
content = models.CharField(max_length=255)
pub_date = models.DateTimeField(auto_now_add=True)
# index = GenericRelation(Index) # 关联到通用模型类的表
# TODO: 问题1 :如何在其他的模型类中,生成一条数据的时候,在基类中也创建一条数据(代码复用性)
# def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
# content_type = ContentType.objects.get_or_create(self)
# # self.index.get_or_create(pub_data=self.pub_date)
Index.objects.get_or_create(
content_type=content_type,
object_id=self.id,
pub_date=self.pub_date
)
class Article(models.Model):
"""文章"""
title = models.TextField()
pub_date = models.DateTimeField(auto_now_add=True)
# index = GenericRelation(Index)
# def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
# content_type = ContentType.objects.get_or_create(self)
# # self.index.get_or_create(pub_data=self.pub_date)
# Index.objects.get_or_create(
# content_type=content_type,
# object_id=self.id,
# pub_date=self.pub_date
# )
class Question(models.Model):
"""问题"""
title = models.TextField()
pub_date = models.DateTimeField(auto_now_add=True)
# index = GenericRelation(Index)
# def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
# content_type = ContentType.objects.get_or_create(self)
# # self.index.get_or_create(pub_data=self.pub_date)
# Index.objects.get_or_create(
# content_type=content_type,
# object_id=self.id,
# pub_date=self.pub_date
# )
def create_index(sender, instance, **kwargs):
"""
这里使用信号量机制,每当完成一次创建,就关联到ContentType中创建一条数据
sender: 发送者
instance:实例对象
"""
if "created" in kwargs: # TODO: 每次创建的时候触发
content_type = ContentType.objects.get_for_model(instance)
Index.objects.get_or_create(
content_type=content_type,
object_id=instance.id,
pub_date=instance.pub_date
)
# 固定写法
post_save.connect(create_index, sender=News)
post_save.connect(create_index, sender=Article)
post_save.connect(create_index, sender=Question)
评论区