******

Django的contenttype表中存放发的是app名称和模型的对应关系

contentType使用方式
- 导入模块
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
- 定义models
class PythonBasic(models.Model):
course_name = models.CharField(max_length=32)


class Oop(models.Model):
course_name = models.CharField(max_length=32)


class Coupon(models.Model):
coupon_name = models.CharField(max_length=32)
# 关联到contenttype外键,用来存放对应的表的id(在contenttype表中的id)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
# 关联对应的商品的id
object_id = models.PositiveIntegerField()
# 关联的对象商品
content_object = GenericForeignKey("content_type", "object_id")
- 使用
class CourseView(APIView):
def get(self, request):
pb = ContentType.objects.get(app_label="myapp", model="pythonbasic")
# model_class()获取对应的表类
object_id = pb.model_class().objects.get(pk=3)
# 其中的关系我们可以使用content_object进行关联,它相当于一个管理器
# 我们将对应的对象给他,他会自动给字段建立关系
# 但是其实我对于它的应用了解还不是很多,如果需要请看django文档
Coupon.objects.create(coupon_name="python通关优惠券", content_object=object_id)
return HttpResponse("ok")
总结:
关于它的使用时机,其实就是如果一个模型类与多个类之间都存在外键关系的时候。比如订单表与书籍表以及衣服表,都会产生订单,但是万一还有其他类的商品也要关联订单的时候,我们可以使用,contentType进行关联。其实就是一个万能的中间表,可以关联任何的其他表。

  当一张表作为多个表的FK,就可以使用content_type表;例如上面的优惠券表,被食物和衣服当作FK,数据库表一旦建立就难以更改,如果以后需要增加电器等表并把优惠券表作为FK表,这时就不能做到在优惠券表增加列字段electr_id,因为表只能增加行记录而不能增加列字段(虽然扩张表字段也可以,但是一个是浪费空间,第二个就是麻烦难道没有一种商品类型你就加一个字段,累死了),因此就可以使用content_type表来将表与表中的对象进行关联,从而做到不增加列字段的情况下增加FK关系。

  在使用content_type表时,需要在FK表中增加content_type作为FK字段,并增加GenericForeignKey便于优惠券表记录的建立以及单个优惠券对象对应的其他商品的查找。在优惠券表关联的“一”的关系表中增加GenericRelation字段便于查找关联的优惠券记录的查找

  

def get_order_serializer(queryset):
class OrderItemSerializer(StandardModelSerializer):
object_id = serializers.PrimaryKeyRelatedField(queryset=queryset)
price = serializers.DecimalField(max_digits=10, decimal_places=2) class Meta:
model = OrderItem
fields = ("price", "object_id") class OrderCSerializer(StandardModelSerializer):
item = OrderItemSerializer(many=True) class Meta:
model = Order
fields = ("item",) return OrderCSerializer, OrderItemSerializer class OrderItemSerializer(StandardModelSerializer):
name = serializers.CharField(source="content_type.name") class Meta:
model = OrderItem
fields = ('price', "name") class OrderSerializer(StandardModelSerializer):
item = OrderItemSerializer(many=True) # 与嵌套的serializer中的model表中的related_name关联 class Meta:
model = Order
fields = ("amount", "item")
class OrderViewSet(base_view.BaseGenericViewSet,
CreateModelMixin,
ListModelMixin):
queryset = Order.objects.all()
serializer_class = OrderSerializer
filter_backends = (StandardOrderingFilter, StandardFilterBackend, StandardSearchFilter)
search_fields = ("amount", "id")
filter_fields = ("amount", "id")
ordering = "id" def create(self, request: Request, model, app_label):
content_type = ContentType.objects.get(model=model, app_label=app_label)
prd_model = content_type.model_class()
order_ser, order_item_ser = get_order_serializer(prd_model._default_manager.all())
serializer = order_ser(data=request.data)
serializer.is_valid()
data = serializer.validated_data
order = Order.objects.create(amount=0)
total_amount = 0
for post_item in data["item"]:
content_object = post_item["object_id"]
price = content_object.get_price
if price != post_item["price"]:
raise Invalid
total_amount += int(price)
OrderItem.objects.create(content_object=content_object, price=price, order=order)
order.amount = total_amount
order.save()
ser = self.get_serializer(order)
headers = self.get_success_headers(ser.data)
return Response(data=ser.data, headers=headers, status=status.HTTP_201_CREATED)

view.py

class Order(models.Model):
amount = models.DecimalField(max_digits=10, decimal_places=2, default=-1) class OrderItem(models.Model):
content_type = models.ForeignKey(ContentType, on_delete=models.DO_NOTHING)
object_id = models.IntegerField()
content_object = GenericForeignKey()
price = models.DecimalField(max_digits=10, decimal_places=2)
order = models.ForeignKey(db_constraint=False, db_column="order_id",
db_index=True, on_delete=models.DO_NOTHING,
related_name="item", to="Order",
to_field="id") # 设置的related_name是很关键的,因为在serializer传入数据的时候,Orde表会根据它进行查找,如果名称不对会发生错误 class Product(models.Model):
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=10, decimal_places=2) @property
def get_price(self):
return self.price class Meta:
db_table = "product"
verbose_name_plural = verbose_name = "product" def __str__(self):
return "{}".format(self.name)
 contenttypes框架¶
Django包含一个contenttypes应用程序,可以跟踪Django驱动的项目中安装的所有模型,为您的模型提供高级通用界面。 概述¶
contenttypes应用程序的核心是ContentType生活在的 模型 django.contrib.contenttypes.models.ContentType。ContentType表示和存储有关项目中安装的模型的信息的实例, 以及安装ContentType新模型时自动创建的新实例 。 ContentType具有返回它们所代表的模型类以及从这些模型查询对象的方法的实例。ContentType 还有一个自定义管理器,它添加了使用ContentType和获取ContentType 特定模型实例的方法。 模型之间的关系 ContentType也可用于启用某个模型的实例与已安装的任何模型的实例之间的“通用”关系。 安装contenttypes框架¶
contenttypes框架包含在由其INSTALLED_APPS创建的默认 列表中,但如果您已将其删除,或者您手动设置了 列表,则可以通过添加到您的设置来启用它 。django-admin startprojectINSTALLED_APPS'django.contrib.contenttypes'INSTALLED_APPS 安装contenttypes框架通常是个好主意; Django的其他几个捆绑应用程序需要它: 管理应用程序使用它来记录通过管理界面添加或更改的每个对象的历史记录。
Django 使用它将用户权限绑定到特定模型。authentication framework
该ContentType模型¶
类ContentType¶
每个实例ContentType 都有两个字段,它们一起唯一地描述了已安装的模型: app_label¶ (这个是你app的名称)
模型所属应用程序的名称。这取自app_label模型的属性,仅包括应用程序的Python导入路径的 最后部分; django.contrib.contenttypes,例如,成为一个 app_label的contenttypes。 model¶ (这个是你模型的表名称,全小写)
模型类的名称。 此外,还提供以下房产: name¶
人类可读的内容类型名称。这取自verbose_name 模型的 属性。 让我们看一个例子来看看它是如何工作的。如果您已安装该contenttypes应用程序,然后添加 到您的 设置并运行以进行安装,则该模型将安装到您的数据库中。除此之外,还将使用以下值创建一个新实例 :the sites applicationINSTALLED_APPSmanage.py migratedjango.contrib.sites.models.SiteContentType app_label 将被设置为'sites'(Python路径的最后一部分django.contrib.sites)。
model 将被设置为'site'。
ContentType实例上的方法¶
每个ContentType实例都有一些方法,允许您从ContentType实例获取 它所代表的模型,或者从该模型中检索对象:

  content_type = Content_type.objects.get(app_label="XXX", model="xxx") (下面用的ContConentType=content_type.model_class()就是这样查找出来的)
  还有一个办法可以拿到模型多有的对象 content_type.model_class._default_manager.all() (红色部分其实就是objects模型管理器对象)
    
ContConentType.get_object_for_this_type(** kwargs)¶ (uuid="ssfdsfa")其实就是传入对应的字段与get相同
为 表示的模型获取一组有效的查找参数ContentType,并 在该模型上执行,返回相应的对象。a get() lookup ContentType.model_class()¶ # 可以拿到对应的模型 他很重要
返回此ContentType实例表示的模型类 。 例如,我们可以仰望 ContentType的 User模型: >>> from django.contrib.contenttypes.models import ContentType
>>> user_type = ContentType.objects.get(app_label='auth', model='user')
>>> user_type
<ContentType: user>
然后使用它来查询特定的 User,或者访问User模型类: >>> user_type.model_class()
55 <class 'django.contrib.auth.models.User'>
>>> user_type.get_object_for_this_type(username='Guido')
<User: Guido>
一起, get_object_for_this_type() 并model_class()启用两个非常重要的用例: 使用这些方法,您可以编写对任何已安装模型执行查询的高级通用代码 - 您可以在运行时将一个app_label并 model传入 ContentType查找,然后使用模型类或从中检索对象。
您可以将另一个模型与 ContentType将其实例绑定到特定模型类的方法相关联,并使用这些方法来访问这些模型类。
Django的几个捆绑应用程序使用后一种技术。例如, 在Django的身份验证框架中使用带有外键的 模型; 这可以 代表“可以添加博客条目”或“可以删除新闻故事”等概念。the permissions systemPermissionContentTypePermission 该ContentTypeManager¶
类ContentTypeManager¶
ContentType还有一个自定义管理器,ContentTypeManager它添加了以下方法: clear_cache()¶
清除用于ContentType跟踪其已创建ContentType实例的模型 的内部缓存 。您可能不需要自己调用此方法; Django会在需要时自动调用它。 get_for_id(id)¶
ContentType按ID 查找。由于此方法使用相同的共享缓存 get_for_model(),因此优先使用此方法 ContentType.objects.get(pk=id) get_for_model(model,for_concrete_model = True)¶ (传入模型名)
获取模型类或模型的实例,并返回ContentType表示该模型的 实例。for_concrete_model=False允许获取ContentType代理模型。 get_for_models(* models,for_concrete_models = True)¶
获取可变数量的模型类,并返回将模型类映射到ContentType表示它们的实例的字典 。for_concrete_models=False允许获取 ContentType代理模型。 get_by_natural_key(app_label,model)¶
返回ContentType 由给定应用程序标签和模型名称唯一标识的实例。此方法的主要目的是允许 在反序列化期间ContentType通过自然键引用对象。 get_for_model()当您知道需要使用a ContentType但不想在获取模型的元数据以执行手动查找时遇到麻烦,该方法特别有用 : >>> from django.contrib.auth.models import User
>>> ContentType.objects.get_for_model(User)
<ContentType: user>
通用关系¶
从您自己的模型中添加外键,以 ContentType允许模型有效地将自身绑定到另一个模型类,如Permission上面模型的示例 所示。但是可以更进一步,用于 ContentType在模型之间实现真正通用(有时称为“多态”)关系。 一个简单的例子是标记系统,它可能如下所示: from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import models class TaggedItem(models.Model):
tag = models.SlugField()
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id') def __str__(self):
return self.tag
法线ForeignKey只能“指向”另一个模型,这意味着如果TaggedItem模型使用了 ForeignKey它,则必须选择一个且只有一个模型来存储标签。contenttypes应用程序提供了一个特殊的字段类型(GenericForeignKey),它可以解决这个问题,并允许关系与任何模型: 类GenericForeignKey¶
设置一个有三个部分 GenericForeignKey: 给你的模型ForeignKey 来ContentType。该字段的通常名称是“content_type”。
为您的模型提供一个字段,该字段可以存储您要与之相关的模型中的主键值。对于大多数模型,这意味着一个 PositiveIntegerField。该字段的通常名称是“object_id”。
给你的模型a GenericForeignKey,并传递上述两个字段的名称。如果这些字段名为“content_type”和“object_id”,则可以省略 - 这些是GenericForeignKey将要查找的默认字段名称 。
for_concrete_model¶
如果False,该字段将能够引用代理模型。默认是True。这反映了这个for_concrete_model论点 get_for_model()。 主键类型兼容性 “object_id”字段不必与相关模型上的主键字段具有相同的类型,但它们的主键值必须通过其get_db_prep_value()方法可强制化为与“object_id”字段相同的类型 。 例如,如果要允许与具有任一IntegerField或 CharField主键字段的模型的泛型关系 ,则可以使用CharField模型上的“object_id”字段,因为整数可以通过强制转换为字符串get_db_prep_value()。 为了获得最大的灵活性,您可以使用 TextField没有定义最大长度的a,但是这可能会导致严重的性能损失,具体取决于您的数据库后端。 对于哪种字段类型最好,没有一种通用的解决方案。您应该评估您希望指向的模型,并确定哪种解决方案对您的用例最有效。 序列化ContentType对象的引用 如果fixtures从实现泛型关系的模型中序列化数据(例如,生成时 ),则应该使用自然键来唯一标识相关ContentType 对象。请参阅自然键和 更多信息。dumpdata --natural-foreign 这将启用类似于用于正常的API的API ForeignKey; 每个TaggedItem都有一个content_object返回与其相关的对象的字段,您也可以在创建时使用该字段或使用它TaggedItem: >>> from django.contrib.auth.models import User
>>> guido = User.objects.get(username='Guido')
>>> t = TaggedItem(content_object=guido, tag='bdfl')
>>> t.save()
>>> t.content_object
<User: Guido>
如果删除了相关对象,则content_type和object_id字段仍将设置为其原始值并GenericForeignKey返回 None: >>> guido.delete()
>>> t.content_object # returns None
由于方式GenericForeignKey 实现,你不能直接使用的过滤器等领域(filter() 以及exclude()通过数据库API,例如)。由于 GenericForeignKey不正常的领域对象,这些例子不工作: # This will fail
>>> TaggedItem.objects.filter(content_object=guido)
# This will also fail
>>> TaggedItem.objects.get(content_object=guido)
同样,GenericForeignKeys没有出现在ModelForms中。 反向泛型关系¶
类GenericRelation¶
related_query_name¶
默认情况下,相关对象与该对象的关系不存在。设置related_query_name创建从相关对象回到此关系的关系。这允许从相关对象查询和过滤。 如果您知道最常使用的模型,还可以添加“反向”通用关系以启用其他API。例如: from django.contrib.contenttypes.fields import GenericRelation
from django.db import models class Bookmark(models.Model):
url = models.URLField()
tags = GenericRelation(TaggedItem)
Bookmark每个实例都有一个tags属性,可以用来检索它们的关联TaggedItems: >>> b = Bookmark(url='https://www.djangoproject.com/')
>>> b.save()
>>> t1 = TaggedItem(content_object=b, tag='django')
>>> t1.save()
>>> t2 = TaggedItem(content_object=b, tag='python')
>>> t2.save()
>>> b.tags.all()
<QuerySet [<TaggedItem: django>, <TaggedItem: python>]>
GenericRelation使用 related_query_nameset 定义允许从相关对象查询: tags = GenericRelation(TaggedItem, related_query_name='bookmark')
这使得过滤,排序等查询操作上的Bookmark 来自TaggedItem: >>> # Get all tags belonging to bookmarks containing `django` in the url
>>> TaggedItem.objects.filter(bookmark__url__contains='django')
<QuerySet [<TaggedItem: django>, <TaggedItem: python>]>
当然,如果您不添加related_query_name,您可以手动执行相同类型的查找: >>> bookmarks = Bookmark.objects.filter(url__contains='django')
>>> bookmark_type = ContentType.objects.get_for_model(Bookmark)
>>> TaggedItem.objects.filter(content_type__pk=bookmark_type.id, object_id__in=bookmarks)
<QuerySet [<TaggedItem: django>, <TaggedItem: python>]>
就像GenericForeignKey 接受content-type和object-ID字段的名称一样,也是如此 GenericRelation; 如果具有通用外键的模型对这些字段使用非默认名称,则必须在设置字段时传递字段的名称 GenericRelation。例如,如果TaggedItem上面提到的模型使用了命名的字段content_type_fk并 object_primary_key创建了它的通用外键,那么 GenericRelation需要像这样定义返回它: tags = GenericRelation(
TaggedItem,
content_type_field='content_type_fk',
object_id_field='object_primary_key',
)
另请注意,如果删除具有a的对象,则 GenericRelation任何GenericForeignKey 指向该对象的对象也将被删除。在上面的示例中,这意味着如果Bookmark删除了某个对象,TaggedItem则会同时删除指向该对象的任何对象。 不同ForeignKey, GenericForeignKey不接受on_delete自定义此行为的参数; 如果需要,您可以通过不使用来避免级联删除 GenericRelation,并且可以通过pre_delete 信号提供替代行为。 通用关系和聚合¶
Django的数据库聚合API适用于 GenericRelation。例如,您可以找出所有书签的标签数量: >>> Bookmark.objects.aggregate(Count('tags'))
{'tags__count': 3}
表格中的通用关系¶
该django.contrib.contenttypes.forms模块提供: BaseGenericInlineFormSet
一个formset工厂,generic_inlineformset_factory()用于 GenericForeignKey。
类BaseGenericInlineFormSet¶
generic_inlineformset_factory(model,form = ModelForm,formset = BaseGenericInlineFormSet,ct_field =“content_type”,fk_field =“object_id”,fields = None,exclude = None,extra = 3,can_order = False,can_delete = True,max_num = None,formfield_callback = None,validate_max = False,for_concrete_model = True,min_num = None,validate_min = False)¶
返回一个GenericInlineFormSet使用 modelformset_factory()。 您必须提供ct_field与fk_field他们是否是不同的默认值,content_type并object_id分别。其它参数类似于那些记录 modelformset_factory()和 inlineformset_factory()。 该for_concrete_model参数对应 for_concrete_model 的参数GenericForeignKey。 管理中的通用关系¶
该django.contrib.contenttypes.admin模块提供 GenericTabularInline和 GenericStackedInline(子类 GenericInlineModelAdmin) 这些类和函数支持在表单和管理员中使用通用关系。有关更多信息,请参阅模型formset和 管理文档。 类GenericInlineModelAdmin¶
在GenericInlineModelAdmin 类继承自的所有属性 InlineModelAdmin类。但是,它增加了一些用于处理泛型关​​系的东西: ct_field¶
ContentType模型上的外键字段的名称 。默认为content_type。 ct_fk_field¶
表示相关对象ID的整数字段的名称。默认为object_id。 类GenericTabularInline¶
类GenericStackedInline¶
GenericInlineModelAdmin分别具有堆叠和表格布局的子类。

11.关于django的content_type表的更多相关文章

  1. url路由、模板语言、ajax、用django框架创建表

    1.后台管理的左侧菜单,默认只有第一个页签下面的选项是显示的,点了别的页签再显示别的页签下面的选项,问题是:点了任何菜单的选项后,左侧菜单又成了第一个页签的选项显示,别的页签隐藏,也就是左侧的菜单刷新 ...

  2. Django 组件content_type

    content type: django内置组件,这个组件帮忙做连表操作(混搭连表) 适用场景:适用于一张表与多张表同时做关联的时候.直接导入就可以使用了. 关联数据库所有的表:可以快速插入数据,并且 ...

  3. Django之mysql表单操作

    在Django之ORM模型中总结过django下mysql表的创建操作,接下来总结mysql表记录操作,包括表记录的增.删.改.查. 1. 添加表记录 class UserInfo(models.Mo ...

  4. 转载:Django之form表单

    转载: 一.使用form类创建一个表单 先定义好一个RegForm类: forms.py from django import forms # 导入forms类 class NameForm(form ...

  5. Django开发之路 二(django的models表查询)

    django的models表查询 一.单表查询 (1) all(): 查询所有结果 # 返回的QuerySet类型 (2) filter(**kwargs): 它包含了与所给筛选条件相匹配的对象 #返 ...

  6. Django 的ORM 表间操作

    Django之ORM表间操作   之前完成了简单的数据库数据增加操作.这次学习更多的表间操作. 单表操作 增加 方式一 b = Book(title="Python基础", pub ...

  7. Django之form表单详解

    构建一个表单 假设你想在你的网站上创建一个简单的表单,以获得用户的名字.你需要类似这样的模板: <form action="/your-name/" method=" ...

  8. Django生成数据表时报错

    Django生成数据表时报错 WARNINGS: ?: (mysql.W002) MySQL Strict Mode is not set for database connection 'defau ...

  9. Django ORM 多表操作

    目录 Django ORM 多表操作 表模型 表关系 创建模型 逆向到表模型 插入数据 ORM 添加数据(添加外键) 一对多(外键 ForeignKey) 一对一 (OneToOneFeild) 多对 ...

随机推荐

  1. 利用Python如何实现数据驱动的接口自动化测试

    前言 大家在接口测试的过程中,很多时候会用到对CSV的读取操作,本文主要说明Python3对CSV的写入和读取.下面话不多说了,来一起看看详细的介绍吧. 1.需求 某API,GET方法,token,m ...

  2. 【LeetCode】714、买卖股票的最佳时机含手续费

    Best Time to Buy and Sell Stock with Transaction Fee 题目等级:Medium 题目描述: Your are given an array of in ...

  3. Python 命令行解析模块 —— argparse

    argparse是python标准库里面用来处理命令行参数的库,基本使用步骤如下: 1.import argparse    导入模块 2.parser = argparse.ArgumentPars ...

  4. python GIL全局解释器锁与互斥锁 目录

    python 并发编程 多线程 GIL全局解释器锁基本概念 python 并发编程 多线程 GIL与Lock python 并发编程 多线程 GIL与多线程

  5. windeployqt.exe 发布windows下qt产生的exe程序

    以官方 Qt 5.4.0+MinGW 开发环境为例,从开始菜单-->Qt 5.4.0-->5.4-->MinGW 4.9 (32-bit)-->Qt 5.4 for Deskt ...

  6. 小记-----一些linux操作小操作

    lrzsz工具 window系统与linux系统 文件互传      1.在linux系统命令行:sudo yum install lrzsz  或者  yum install lrzsz (输入一个 ...

  7. centos 防火墙 iptables firewalld SELinux

    参考 Centos7 只启用iptables 禁用firewalld功能 java.net.NoRouteToHostException: 没有到主机的路由 相关内容 centos7 中才开始引用fi ...

  8. 3种Redis分布式锁的对比

    我们通常使用的synchronized或者Lock都是线程锁,对同一个JVM进程内的多个线程有效.因为锁的本质 是内存中存放一个标记,记录获取锁的线程是谁,这个标记对每个线程都可见.然而我们启动的多个 ...

  9. mybatis多对多关联关系映射

    mybatis多对多关联关系映射 多对多关系在java类实体中表示为,一个类中包含了集合为另一个类的属性.而这连个实体都需要包含对方的集合类的属性. 例如:订单和商品,一个订单包含多个商品,一个商品又 ...

  10. 使用Servlet实现验证码

    没有验证码带来的问题 对特定用户不断登录破解密码. 对某个网站创建账户. 对某个网站提交垃圾数据. 对某个网站刷票.  通过验证码由用户肉眼识别其中的验证码信息,从而区分用户是人还是计算机. 定义: ...