zoukankan      html  css  js  c++  java
  • 中介模型以及优化查询以及CBV模式

    一、中介模型:多对多添加的时候用到中介模型

    自己创建的第三张表就属于是中介模型
    class Article(models.Model):
        '''
        文章表
        '''
        title = models.CharField(max_length=64,verbose_name="文章标题")
        summary = models.CharField(max_length=244, verbose_name="文章概要")
        create_time = models.DateTimeField(verbose_name="创建时间",auto_now_add=True)
        update_time = models.DateTimeField(verbose_name="修改时间",auto_now=True)
        up_count = models.IntegerField(verbose_name="点赞数",default=0)
        down_count = models.IntegerField(verbose_name="点灭数",default=0)
        comment_count = models.IntegerField(verbose_name="评论数",default=0)
        read_count = models.IntegerField(verbose_name="阅读数",default=0)
    
        user = models.ForeignKey(to="UserInfo",verbose_name="所属作者",null=True,blank=True)
        classify = models.ForeignKey(to="Classfication",verbose_name="所属类别",null=True,blank=True)
        tags = models.ManyToManyField(to="Tag",through="Article2tag",through_fields=('article', 'tag'),verbose_name="所属标签")
        site_article_category = models.ForeignKey(to="SiteArticleCategory",verbose_name="所属文章分类",null=True,blank=True)
        class Meta:
            verbose_name_plural = "文章表"
        def __str__(self):
            return self.title
    
    
    
    
    class Tag(models.Model):
        '''标签表'''
        name = models.CharField(max_length=32,verbose_name="标签名")
        blog = models.ForeignKey(to="Blog",verbose_name="所属博客")
        class Meta:
            verbose_name_plural = "标签表"
    
        def __str__(self):
            return self.name
    
    
    class Article2tag(models.Model):
        article = models.ForeignKey(verbose_name="文章",to="Article")
        tag = models.ForeignKey(verbose_name="标签",to="Tag")
        class Meta:
            verbose_name="文章和标签关系表"
            '''联合唯一'''
            unique_together = [
                ("article","tag")
            ]
        def __str__(self):
            return self.article.title + "  "+self.tag.name

    像是这样自己创建的第三张表就属于是中介模型。一般就Django会给我们自动创建第三张表,
    人家自己创建的只是有关系字段,不能在增加其他的字段了,
    如果根据需求添加其他字段,不需要ManytoMany自己创建第三张表就自己设置第三张表
    这就需要我们自己去创建第三张表。
    当然我现在设计的
    Article2tag这个第三张表就可以在里面添加其他你需要的字段。

    如果用了中介模型了,就不能在用add,remove了

    为什么不能这样做? 这是因为你不能只创建 article和 tag之间的关联关系,你还要指定 Membership模型中所需要的所有信息;而简单的addcreate 和赋值语句是做不到这一点的。所以它们不能在使用中介模型的多对多关系中使用。此时,唯一的办法就是创建中介模型的实例。

     remove()方法被禁用也是出于同样的原因。但是clear() 方法却是可用的。它可以清空某个实例所有的多对多关系:

    cate = request.POST.get("cate")
    tag = request.POST.getlist("tag")
    article_obj = models.Article.objects.create(title=title,summary=content[0:30],create_time=datetime.datetime.now(),user=request.user,classify_id = cate)
    models.Article_detail.objects.create(content=content,article=article_obj)
    if tag:
      for i in tag:   #[2,4]
          models.Article2tag.objects.create(tag_id=i,article_id=article_obj.id)   #直接从关系表里面去查

    remove()方法被禁用也是出于同样的原因。但是clear() 方法却是可用的。它可以清空某个实例所有的多对多关系:

    二、优化查询

    简单使用

    对于一对一字段(OneToOneField)和外键字段(ForeignKey),可以使用select_related 来对QuerySet进行优化。

    select_related 返回一个QuerySet,当执行它的查询时它沿着外键关系查询关联的对象的数据。它会生成一个复杂的查询并引起性能的损耗,但是在以后使用外键关系时将不需要数据库查询。

    简单说,在对QuerySet使用select_related()函数后,Django会获取相应外键对应的对象,从而在之后需要的时候不必再查询数据库了。

    下面的例子解释了普通查询和select_related() 查询的区别。

    查询id=2的文章的分类名称,下面是一个标准的查询:

    
    
    obj = models.Article.objects.get(id=2)
    print(obj.classify.title) #走两次数据库,基于对象的属于子查询,基于双下划线的属于连表查询

    sql是这样的

     1 '''
     2  
     3 SELECT
     4     "blog_article"."nid",
     5     "blog_article"."title",
     6     "blog_article"."desc",
     7     "blog_article"."read_count",
     8     "blog_article"."comment_count",
     9     "blog_article"."up_count",
    10     "blog_article"."down_count",
    11     "blog_article"."category_id",
    12     "blog_article"."create_time",
    13      "blog_article"."blog_id",
    14      "blog_article"."article_type_id"
    15              FROM "blog_article"
    16              WHERE "blog_article"."nid" = 2; args=(2,)
    17  
    18 SELECT
    19      "blog_category"."nid",
    20      "blog_category"."title",
    21      "blog_category"."blog_id"
    22               FROM "blog_category"
    23               WHERE "blog_category"."nid" = 4; args=(4,)
    24  
    25  
    26 '''
    View Code

     如果我们使用select_related()函数:

    articleList=models.Article.objects.select_related("category").all()
       
     
        for article_obj in articleList:
            #  Doesn't hit the database, because article_obj.category
            #  has been prepopulated in the previous query.
            print(article_obj.category.title)


    #查询所有书的分类标题
    obj_list=models.Article.objects.select_related("user").select_related("classify").all()
    for obj in obj_list:
    print(obj,"2222222",type(obj))
    print(obj.classify.title)

    # obj_list = models.Article.objects.select_related("user","classify").all()
    # for obj in obj_list:
    # print(obj.classify.title)
    # 要看需求查的数据多不多,如果一次的话就没有必要了
    
    
     1 SELECT
     2      "blog_article"."nid",
     3      "blog_article"."title",
     4      "blog_article"."desc",
     5      "blog_article"."read_count",
     6      "blog_article"."comment_count",
     7      "blog_article"."up_count",
     8      "blog_article"."down_count",
     9      "blog_article"."category_id",
    10      "blog_article"."create_time",
    11      "blog_article"."blog_id",
    12      "blog_article"."article_type_id",
    13  
    14      "blog_category"."nid",
    15      "blog_category"."title",
    16      "blog_category"."blog_id"
    17  
    18 FROM "blog_article"
    19 LEFT OUTER JOIN "blog_category" ON ("blog_article"."category_id" = "blog_category"."nid");
    View Code

    总结

    1. select_related主要针一对一和多对一关系进行优化。
    2. select_related使用SQL的JOIN语句进行优化,通过减少SQL查询的次数来进行优化、提高性能。
    3. 可以通过可变长参数指定需要select_related的字段名。也可以通过使用双下划线“__”连接字段名来实现指定的递归查询。
    4. 没有指定的字段不会缓存,没有指定的深度不会缓存,如果要访问的话Django会再次进行SQL查询。
    5. 也可以通过depth参数指定递归的深度,Django会自动缓存指定深度内所有的字段。如果要访问指定深度外的字段,Django会再次进行SQL查询。
    6. 也接受无参数的调用,Django会尽可能深的递归查询所有的字段。但注意有Django递归的限制和性能的浪费。
    7. Django >= 1.7,链式调用的select_related相当于使用可变长参数。Django < 1.7,链式调用会导致前边的select_related失效,只保留最后一个。

    三、CBV模式

    就是把之前的函数视图用类实现了

    简单测试一下:

    urls.py

    #CBV模式
        url(r'^login_cbv/$', views.Login_cbv.as_view()),
    注意:这里的Login_cbv是类名,它必须后面调用as_view()

    views.py

    from django.views import View
    class Login_cbv(View):
       def get(self,request):  #如果是get请求需要执行的代码
           return render(request,"login_cbv.html")
       def post(self,request): #如果是post请求需要执行的代码
           return HttpResponse(".....")
       def delete(self,request):
           pass
    login_cbv.html
    <form action="/login_cbv/" method="post">
        {% csrf_token %}
        姓名:<input type="text">
        <input type="submit">
    </form>

    对于form表单只支持post和get请求,对于ajax请求支持8种,

    http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

    四、整体插入

    创建对象时,尽可能使用bulk_create()来减少SQL查询的数量。例如:
    
    Entry.objects.bulk_create([
        Entry(headline="Python 3.0 Released"),
        Entry(headline="Python 3.1 Planned")
    ])
    ...更优于:
    
    Entry.objects.create(headline="Python 3.0 Released")
    Entry.objects.create(headline="Python 3.1 Planned")
    注意该方法有很多注意事项,所以确保它适用于你的情况。
    
    这也可以用在ManyToManyFields中,所以:
    
    my_band.members.add(me, my_friend)
    ...更优于:
    
    my_band.members.add(me)
    my_band.members.add(my_friend)
    ...其中Bands和Artists具有多对多关联。
    

      

  • 相关阅读:
    文件读取
    命名实体识别训练集汇总(一直更新)
    基于PyTorch的Seq2Seq翻译模型详细注释介绍(一)
    python if elif else 区别
    乱码
    dataframe添加元素指定为列表,不同for循环命名空间下的变量重复问题
    tensorflow兼容处理 tensorflow.compat.v1
    Kerberos
    Hadoop集群datanode磁盘不均衡的解决方案
    Saltstack
  • 原文地址:https://www.cnblogs.com/morgana/p/8493127.html
Copyright © 2011-2022 走看看