Django中contenttypes框架与通用外键总结

ContentType介绍

Django ContentTypes是由Django框架提供的一个核心功能,它对当前项目中所有基于Django驱动的model提供了更高层次的抽象接口。

  • Django权限管理中的Permission借助ContentType实现了对任意models的权限操作。
  • ContenType的通用类型- GenericRelation(通用外键关联),使模型类中的某张表关联到任意的表。

在新建一个项目的时候在installed_app中默认会有contenttypes
在这里插入图片描述

在迁移完数据库后会发现项目的表中存在一张叫做django_content_type的表,表中有两个关键字段:

  • app_label:应用标签,也就是我们每个app模块的名字。
  • model:对应app模块下的模型类名称。
    在这里插入图片描述

这张表就是Django模型管理的表,根据这两个字段我们可以定位到任何一个模型类。

ContentType源码解析

源码位置:

from django.contrib.contenttypes.models import ContentType
在这里插入图片描述

  • 获取自定义模型类例子:

    >>> from django.contrib.contenttypes.models import ContentType
    >>> user_type = ContentType.objects.get(app_label='auth', model='user')
    >>> user_type
    <ContentType: user>
    

在这里插入图片描述

  • 查询模型类中的字段例子:

    1. 先根据上边的例子获取模型类

    2. 查询模型类中的字段

      >>> user_type.model_class()
      <class 'django.contrib.auth.models.User'>
      >>> user_type.get_object_for_this_type(username='Guido')
      <User: Guido>
      

GenericRelation和GenericForeignKey介绍与使用

假如在一个项目中有博客模块、文章模块、图片模块,每一个功能模块都可以让其他人进行评论,也就是说每一个模块的model要关联到评论model。

在不使用通用外键时每个应用的模型类以及评论的模型类如下:

from django.db import models
from django.contrib.auth.models import User

# 博客model
class Post(models.Model):
	author = models.Foreignkey(User, on_delete=models.CASADE)
	body = models.TextField(blank=True)
	
# 文章model
class Article(models.Model):
	author = models.ForeignKey(User, on_delete=models.CASADE)
	body = models.TextField(blank=True)
	
# 图片model
class Picture(models.Model):
	author = models.ForeignKey(User, on_delete=models.CASADE)
	body = models.TextField(blank=True)
	
# 博客评论
class Post_omment(models.Model):
	author = models.ForeignKey(User, on_delete=models.CASADE)
	body = models.TextField(blank=True)
	post = models.ForeignKey(to=Post, on_delete=models.CASADE, null=True)
	
# 图片评论	
class Pic_omment(models.Model):
	author = models.ForeignKey(User, on_delete=models.CASADE)
	body = models.TextField(blank=True)
	pic = models.ForeignKey(to=Picture, on_delete=models.CASADE, null=True)

# 文章评论
class Article_comment(models.Model):
	author = models.ForeignKey(User, on_delete=models.CASADE)
	body = models.TextField(blank=True)
	article = models.ForeignKey(to=Article, on_delete=models.CASADE, null=True)

存在问题:这样对于代码的扩展性不是很友好,每当新增一个模块需要添加评论功能的时候都需要在增加一个该模块的评论model

解决方法:Django框架其实已经考虑到这种情况,并且提供了对应的处理机制,那就是通用外键的使用。

通用外键:将一个自定义model变为一个通用的模型类,该model可以成为任意模型类的外键关联的表。

使用通用外键我们就不用每次新增模块的时候去创建对应的评论模型类,直接让需要的模块关联到定义了通用外键的模型类就可以了。

使用方法

  • 首先要明白表与表之间的关联的意思:

    表与表之间的关联也是记录与记录之间的关联,也就是一个表的一条记录关联到另一张表的一条记录。

  • 想要让两张表关联就要有能够定位到表中的每一条记录的方法,前边讲解的使用ContentType可以定位到一张表,接下来的通用外键就可以帮我们定位到一条记录

  • 定义含有通用外键的评论模型类:

    from django.contrib.contenttypes.models import ContentType
    from django.contrib.contenttypes.fields import GenericForeignKey
    
    
    # 此时的模型类为通用模型类
    class Comment(models.Modle):
    	author = models.ForeignKey(to=User, on_delete=models.CASADE)
    	body = models.TextField(blank=True)
    	# 1. 使用ContenType定位到一张表
    	content_type = models.ForeignKey(ContentType, models.CASADE)
    	# 2. 主键id
    	object_id = models.IntegerField()
    	# 3. 根据1和2定位到一条记录
    	content_object = GenericForeignKey('content_type', 'object_id')
    

    第三步默认情况下传递的参数名称就是content_typeobject_id, 如果第1和第2步的名字和这一样的话,可以缺省参数:content_object = GenericForeignKey()

  • 定义好通用模型类后,在其他模型类中就可以关联到这个通用模型类了:

    from django.contrib.contenttypes.fields import GenericRelation
    from django.db import models
    from django.contrib.auth.models import User
    
    
    # 博客model
    class Post(models.Model):
    	author = models.Foreignkey(User, on_delete=models.CASADE)
    	body = models.TextField(blank=True)
    	# 这样就关联到了评论模型类
    	comments = GenericRelation(Comment)
    	
    	
    # 文章model
    class Article(models.Model):
    	author = models.ForeignKey(User, on_delete=models.CASADE)
    	body = models.TextField(blank=True)
    	# 这样就关联到了评论模型类
    	comments = GenericRelation(Comment)
    	
    	
    # 图片model
    class Picture(models.Model):
    	author = models.ForeignKey(User, on_delete=models.CASADE)
    	body = models.TextField(blank=True)
    	# 这样就关联到了评论模型类
    	comments = GenericRelation(Comment)
    
    
    

    这样不管以后增加了几个功能模块,都不要在重写评论模型类,直接让该模块的模型类关联到通用评论模型类就可以了。

  • 需要注意的是通用模型类的通用外键content_object = GenericForeignKey('content_type', 'object_id')默认是级联删除,且不提供on_delete参数:也就是说当我们删除了文章模块后,关于文章模块的评论也将被删除。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一切如来心秘密

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值