contenttypes 是Django内置的一个应用,可以追踪项目中所有app和model的对应关系,并记录在ContentType表中。

models.py文件的表结构写好后,通过makemigrations和migrate两条命令迁移数据后,在数据库中会自动生成一个django_content_type表:

每当我们创建了新的model并执行数据库迁移后,ContentType表中就会自动新增一条记录。比如我在应用api的models.py中创建表class Electrics(models.Model): pass。从数据库查看ContentType表,显示如下:

ContentType GenericRelation GenericForeignKey示例

#!/usr/bin/python3
# -*- coding:utf-8 -*-
# __author__ = '__Jack__'

from __future__ import unicode_literals
import uuid
from collections import Counter
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericRelation, GenericForeignKey
from django.db import models

from slugify import slugify
from markdownx.models import MarkdownxField
from taggit.managers import TaggableManager
from markdownx.utils import markdownify

class Vote(models.Model):
    """使用Django中的ContentType, 同时关联用户对问题和回答的投票
    投票
    """
    uuid_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='qa_vote',
                             on_delete=models.CASCADE, verbose_name='用户')
    value = models.BooleanField(default=True, verbose_name='赞同或反对')  # True赞同,False反对
    # GenericForeignKey设置
    content_type = models.ForeignKey(ContentType, related_name='votes_on', on_delete=models.CASCADE)
    object_id = models.CharField(max_length=255)
    vote = GenericForeignKey('content_type', 'object_id')  # 等同于GenericForeignKey()

    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')

    class Meta:
        verbose_name = '投票'
        verbose_name_plural = verbose_name
        unique_together = ('user', 'content_type', 'object_id')  # 联合唯一键
        # SQL优化
        index_together = ('content_type', 'object_id')  # 联合唯一索引

class QuestionQuerySet(models.query.QuerySet):
    """自定义QuerySet,提高模型类的可用性"""

    def get_answered(self):
        """已有答案的问题"""
        return self.filter(has_answer=True).select_related('user')

    def get_unanswered(self):
        """未被的回答的问题"""
        return self.filter(has_answer=False).select_related('user')

    def get_counted_tags(self):
        """统计所有问题标签的数量(大于0的)"""
        tag_dict = {}
        for obj in self.all():
            for tag in obj.tags.names():
                if tag not in tag_dict:
                    tag_dict[tag] = 1

                else:
                    tag_dict[tag] += 1
        return tag_dict.items()

class Question(models.Model):
    '''问题'''
    STATUS = (("O", "Open"), ("C", "Close"), ("D", "Draft"))

    user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="q_author",
                             on_delete=models.CASCADE, verbose_name='提问者', default=1)
    title = models.CharField(max_length=255, unique=True, verbose_name='标题')
    slug = models.SlugField(max_length=80, null=True, blank=True, verbose_name='(URL)别名')
    status = models.CharField(max_length=1, choices=STATUS, default='O',
                              verbose_name='问题状态')
    content = MarkdownxField(verbose_name='内容')
    tags = TaggableManager(help_text='多个标签使用,(英文)隔开', verbose_name='标签')
    has_answer = models.BooleanField(default=False, verbose_name="接受回答")  # 是否有接受的回答
    votes = GenericRelation(Vote, verbose_name='投票情况')  # 通过GenericRelation关联到Vote表,不是实际的字段
    created_at = models.DateTimeField(db_index=True, auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')

    objects = QuestionQuerySet.as_manager()

    class Meta:
        verbose_name = '问题'
        verbose_name_plural = verbose_name
        ordering = ("-created_at",)

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.title)
        super(Question, self).save(*args, **kwargs)

    def __str__(self):
        return self.title

    def get_markdown(self):
        return markdownify(self.content)

    def total_votes(self):
        """得票数"""
        dic = Counter(self.votes.values_list('value', flat=True))  # Counter赞同票多少,反对票少数
        return dic[True] - dic[False]

    def get_answers(self):
        """获取所有的回答"""
        return Answer.objects.filter(question=self).select_related('user', 'question')  # self作为参数,当前的问题有多少个回答

    def count_answers(self):
        """回答的数量"""
        return self.get_answers().count()

    def get_upvoters(self):
        """赞同的用户"""
        return [vote.user for vote in self.votes.filter(value=True).select_related('user').prefetch_related('vote')]

    def get_downvoters(self):
        """反对的用户"""
        return [vote.user for vote in self.votes.filter(value=False).select_related('user').prefetch_related('vote')]

class Answer(models.Model):
    '''回答'''
    uuid_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='a_author', on_delete=models.CASCADE,
                             verbose_name='回答者')
    question = models.ForeignKey(Question, on_delete=models.CASCADE, verbose_name='问题')
    content = MarkdownxField(verbose_name='内容')
    is_answer = models.BooleanField(default=False, verbose_name='回答是否被接受')
    votes = GenericRelation(Vote, verbose_name='投票情况')
    created_at = models.DateTimeField(db_index=True, auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')

    class Meta:
        ordering = ('-is_answer', '-created_at')  # 多字段排序
        verbose_name = '回答'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.content

    def get_markdown(self):
        return markdownify(self.content)

    def total_votes(self):
        """得票数"""
        dic = Counter(self.votes.values_list('value', flat=True))  # Counter赞同票多少,反对票少数
        return dic[True] - dic[False]

    def get_upvoters(self):
        """赞同的用户"""
        return [vote.user for vote in self.votes.filter(value=True).select_related('user').prefetch_related('vote')]

    def get_downvoters(self):
        """反对的用户"""
        return [vote.user for vote in self.votes.filter(value=False).select_related('user').prefetch_related('vote')]

    def accept_answer(self):
        """接受回答"""
        # 当一个问题有多个回答的时候,只能采纳一个回答,其它回答一律置为未接受
        answer_set = Answer.objects.filter(question=self.question)  # 查询当前问题的所有回答
        answer_set.update(is_answer=False)  # 一律置为未接受
        # 接受当前回答并保存
        self.is_answer = True
        self.save()
        # 该问题已有被接受的回答,保存
        self.question.has_answer = True
        self.question.save()

# 1.需要返回查询集的逻辑写在QuerySetModel中
# 2.模型类中数据库处理的逻辑写在Models中
# 3.业务相关逻辑的处理写在Views中

  

Django之ContentType,GenericRelation, GenericForeignKey的更多相关文章

  1. Django学习之django自带的contentType表 GenericRelation GenericForeignKey

    Django学习之django自带的contentType表   通过django的contentType表来搞定一个表里面有多个外键的简单处理: 摘自:https://blog.csdn.net/a ...

  2. Django之ContentType组件

    一.理想表结构设计 1.初始构建 1. 场景刚过去的双12,很多电商平台都会对他们的商品进行打折促销活动的,那么我们如果要实现这样的一个场景,改如何设计我们的表? 2. 初始表设计 注释很重要,看看吧 ...

  3. python框架之Django(15)-contenttype模块

    假如有一个书城系统,需要给作者和书籍加上评论功能.如果给每个表单独建一个评论表,那么我们以后要扩展其它模块评论功能的时候,还需要随之新建一张评论表,会显得很冗余.对于这种情况,Django 给我们提供 ...

  4. django 之 ContentType的使用

    1. ContentType 是干什么用的呢: 1. ContentType: 主要的作用就是Django orm的创建表的时候,可以方便多表查询使用,简化多表查询的过程 2.ContentType ...

  5. Django组件(五) Django之ContentType组件

    基础使用 -contenttype组件 -django提供的一个快速连表操作的组件,可以追踪项目中所有的APP和model的对应关系,并记录在ContentType表中. 当我们的项目做数据迁移后,会 ...

  6. Django之ContentType详解

    contenttypes 是Django内置的一个应用,可以追踪项目中所有app和model的对应关系,并记录在ContentType表中. models.py文件的表结构写好后,通过makemigr ...

  7. Django的ContentType框架django_conent_type

    Django包含了一个conenttype应用程序,记录了Django项目中安装的所有模型,为当前项目所有基于Django驱动的model提供了更高层次的抽象接口. 一.概述 ContentTypes ...

  8. Django中contenttype的应用

    content_type表将app名称与其中的表的关系进行保存 通过下边的示例来理解content_type的具体应用: models: from django.db import models fr ...

  9. django之contenttype

    平时开发过程中,我们会经常遇到这么一个类似的场景,比如 不同的课程,有不同的价格策略 不同的课程可使用不同的优惠券(满减券,通用券,专用券) 不同的评论区,支持的评论 就拿  不同的课程,有不同的价格 ...

随机推荐

  1. Apache限制虚拟主机最大连接数和带宽

    1.下载所需安装包: ​ 2.解压到服务器,编译安装: ​ 安装中可能遇到的问题1 提示如下错误:/mnt/vdd/mod_bw.c: In function 'get_bw_rate':/mnt/v ...

  2. JUC-1-volatile

    什么是volatile关键字      volatile是轻量级同步机制,与synchronized相比,他的开销更小一些,同时安全性也有所降低,在一些特定的场景下使用它可以在完成并发目标的基础上有一 ...

  3. beego和bee安装问题解决

    如果使用go mod模式,直接安装bee时会报错: go: github.com/beego/bee imports github.com/beego/bee/cmd imports github.c ...

  4. 源码学习之Spring (系统架构简单解析)

    Spring Framework 系统架构总览图 Spring Framework的模块依赖关系图 Spring Framework各个模块功能说明 Spring核心模块 模块名称 主要功能 Spri ...

  5. Linux系统管理图文详解超详细精心整理

    前言:带你遨游于linux系统管理知识的海洋,沐浴春日里的阳光,循序渐进,看完之后收获满满. 本次讲解基于linux(centos6.5)虚拟机做的测试,centos7估计以后有时间再更新啊. lin ...

  6. IT兄弟连 HTML5教程 HTML语言的语法 2

    HTML颜色值的设置 大多数浏览器都支持颜色名集合,颜色值是一个关键字或一个RGB格式的数字,在网页中用得很多.仅仅有16种颜色名被W3C的HTML 4.0标准所支持,它们是:aqua.black.b ...

  7. kafka 重放 重播 从某个时间点或者offset开始消费

    转自: https://www.jianshu.com/p/932663e9a226 consumer.subscribe(topicA); consumer.poll(100);//正常订阅topi ...

  8. Containers vs Serverless:本质区别是什么?

    在云计算领域,容器和无服务器计算已经占据了发展前列. 作者 | Emra Samdan 翻译 | bocloudresearch 一点历史 在不久以前,应用程序的开发.部署和维护要比现在复杂得多,耗时 ...

  9. PHP框架 fastadmin 根据条件判断字段的显示隐藏

    首先,因为fastadmin的JS里面字段不支持function函数  里面只能填false或true,不能动态判断显示隐藏, 后面通过看文档发现能在表格初始化的地方判断  如图,就可以实现根据lin ...

  10. javascript刷新当前页面的几种方式

    这里总结一下JavaScript刷新当前页面的几种方式. 1.history对象. history.go(0); 2.location对象. location.reload(); location = ...