zoukankan      html  css  js  c++  java
  • django queryset用法总结二

    1、动态条件查询

    简单: design_list = Design.objects.filter(Q(tags__tag__contains = "tag1") and Q(tags__tag__contains = "tag2")
    条件特别多,数量不定,动态的怎么办?
     
    tag_list = ['tag1', 'tag2', 'tag3']
    base_qs = Design.objects.all()
    for t in tag_list:
        base_qs = base_qs.filter(tags__tag__contains=t)

     以上,其实是 and条件, .filter( Q () & Q() )

    想用or 要这样写:

    tags = ['tag1', 'tag2', 'tag3']
    q_objects = Q() # Create an empty Q object to start with
    for t in tags:
        q_objects |= Q(tags__tag__contains=t) # 'or' the Q objects together
    
    designs = Design.objects.filter(q_objects)
        tags = ['tag1', 'tag2', 'tag3']
        q_objects = Q()  # Create an empty Q object to start with
        for t in tags:
            q_objects |= Q(name=t)  # 'or' the Q objects together
    
        print(str(Student.objects.values('name').filter(q_objects).query))

     输出: SELECT "d3_student"."name" FROM "d3_student" WHERE ("d3_student"."name" = tag1 OR "d3_student"."name" = tag2 OR "d3_student"."name" = tag3)

      除了   |=  还有  &=    看如下例子

       q_objects = Q()
              for f in self.get_form_fields():
                  if self.form.cleaned_data.get(f):
                      q_objects &= Q(**{f+'__icontains':self.form.cleaned_data[f]})

      

    2、group by  (annotate, aggregate)

      (1) aggregate后,变为dict,不是queryset

     
    >>> from django.db.models import Avg, Max, Min, Sum, Count
    >>> User.objects.all().aggregate(Avg('id'))
    {'id__avg': 7.571428571428571}
    >>> User.objects.all().aggregate(Max('id'))
    {'id__max': 15}
    >>> User.objects.all().aggregate(Min('id'))
    {'id__min': 1}
    >>> User.objects.all().aggregate(Sum('id'))
    {'id__sum': 106}

     (2)annotate是增加新的一列,结果仍是queryset

    class Author(models.Model):
        name = models.CharField(max_length=100)
    
    class Book(models.Model):
        name = models.CharField(max_length=300)
        rating = models.FloatField()
        authors = models.ManyToManyField(Author)
    
    Author.objects.values('name').annotate(average_rating=Avg('book__rating'))

    
    

      上面例子, 相当于最传统的guoup  : select auther.name, Avg(book.rating) from  auther, book  where auther.id=book.author_id  group by auther.name

      会合并相同的name,计算rating的平均值。 group by 一定是被查询字段的非计算列

     a=AccessAttempt.objects.values('ip_address').annotate(sum_times=Sum('failures_since_start'))
    print(a)
    输出:<QuerySet [{'ip_address': '127.0.0.1', 'sum_times': 5}]>

    a = AccessAttempt.objects.filter(ip_address='127.0.0.1').aggregate(sum_times=Sum('failures_since_start')) print(a) print(a['sum_times'])

    输出:

    {'sum_times': 5}
    5

    再看看下面例子:

    mysql> select * from foo_personmodel;
    +----+-------+-----+
    | id | name  | age |
    +----+-------+-----+
    |  1 | tim   |  16 |
    |  2 | jerry |  27 |
    |  3 | marry |  18 |
    |  4 | tim   |  20 |
    |  5 | alis  |  17 |
    +----+-------+-----+
    5 rows in set (0.00 sec)

     orm

    PersonModel.objects.values("name")
    <QuerySet [{'name': 'tim'}, {'name': 'jerry'}, {'name': 'marry'}, {'name': 'tim'}, {'name': 'alis'}]>

    sql

    mysql> select name,count(id) as counts from foo_personmodel group by name;
    +-------+--------+
    | name  | counts |
    +-------+--------+
    | tim   |      2 |
    | jerry |      1 |
    | marry |      1 |
    | alis  |      1 |
    +-------+--------+
    4 rows in set (0.00 sec)

    orm

    PersonModel.objects.values("name").annotate(counts=Count(id))
    <QuerySet [{'name': 'tim', 'counts': 2}, {'name': 'jerry', 'counts': 1}, {'name': 'marry', 'counts': 1}, {'name': 'alis', 'counts': 1}]>

    当 values 和 annotate 一起使用的时候,values 就承担起了 group by 的角色。并且自动去掉了重项

    3、如何确保table只有一行数据

     class Origin(models.Model):
        name = models.CharField(max_length=100)
    
        def save(self, *args, **kwargs):
            if self.__class__.objects.count():
                self.pk = self.__class__.objects.first().pk
            super().save(*args, **kwargs)

     PK设置相同的值,就不会add,而是update . 

    如何复制或者克隆一行数据

    In [2]: Hero.objects.all().count()
    Out[2]: 4
    
    In [3]: hero = Hero.objects.first()
    
    In [4]: hero.pk = None
    
    In [5]: hero.save()
    
    In [6]: Hero.objects.all().count()
    Out[6]: 5

    4、insert一个table时候,自动更新其他table

     
    class Category(models.Model):
        name = models.CharField(max_length=100)
        hero_count = models.PositiveIntegerField()
        villain_count = models.PositiveIntegerField()
        class Meta:
            verbose_name_plural = "Categories"
    
    class Hero(models.Model):
        name = models.CharField(max_length=100)
        category = models.ForeignKey(Category, on_delete=models.CASCADE)
    
    class Villain(models.Model):
        name = models.CharField(max_length=100)
        category = models.ForeignKey(Category, on_delete=models.CASCADE)

     自动更新举例:

    class Hero(models.Model):
    
        def save(self, *args, **kwargs):
            if not self.pk:
                Category.objects.filter(pk=self.category_id).update(hero_count=F('hero_count')+1)
            super().save(*args, **kwargs)
    
    class Villain(models.Model):
    
        def save(self, *args, **kwargs):
            if not self.pk:
                Category.objects.filter(pk=self.category_id).update(villain_count=F('villain_count')+1)
            super().save(*args, **kwargs)

    注意: 直接self.category.hero_count += 1 这样写的话,update操作也会+1

    如果用signal,相同逻辑可以这样写:

    from django.db.models.signals import pre_save
    from django.dispatch import receiver
    
    @receiver(pre_save, sender=Hero, dispatch_uid="update_hero_count")
    def update_hero_count(sender, **kwargs):
        hero = kwargs['instance']
        if hero.pk:
            Category.objects.filter(pk=hero.category_id).update(hero_count=F('hero_count')+1)
    
    @receiver(pre_save, sender=Villain, dispatch_uid="update_villain_count")
    def update_villain_count(sender, **kwargs):
        villain = kwargs['instance']
        if villain.pk:
            Category.objects.filter(pk=villain.category_id).update(villain_count=F('villain_count')+1)

    那么, 使 扩展save()还是用signal呢?  建议扩展save(), 简单好理解。 但是如果涉及第三方app更新这个table,就只能用signal了

    5、扩展定制truncate

    普通删除可以

     
    >>> Category.objects.all().count()
    7
    >>> Category.objects.all().delete()
    (7, {'entity.Category': 7})
    >>> Category.objects.all().count()
    0

    以上就是DELETE FROM ... , 但是如果是海量数据表,就会很慢,可以用如下方法

    class Category(models.Model):
        # ...
    
        @classmethod
        def truncate(cls):
            with connection.cursor() as cursor:
                cursor.execute('TRUNCATE TABLE "{0}" CASCADE'.format(cls._meta.db_table))

    可以Category.truncate()来删除数据。

    6、How to convert string to datetime and store in database

    日期字符串不能直接存储在date field字段,可以这样做

     
    >>> user = User.objects.get(id=1)
    >>> date_str = "2018-03-11"
    >>> from django.utils.dateparse import parse_date // Way 1
    >>> temp_date = parse_date(date_str)
    >>> a1 = Article(headline="String converted to date", pub_date=temp_date, reporter=user)
    >>> a1.save()
    >>> a1.pub_date
    datetime.date(2018, 3, 11)
    >>> from datetime import datetime // Way 2
    >>> temp_date = datetime.strptime(date_str, "%Y-%m-%d").date()
    >>> a2 = Article(headline="String converted to date way 2", pub_date=temp_date, reporter=user)
    >>> a2.save()
    >>> a2.pub_date
    datetime.date(2018, 3, 11)

    7、使用uuid,代替id做为pk, 因为Id默认是数字,容易被记住和猜到,所以用uuid

     
    import uuid
    from django.db import models
    
    class Event(models.Model):
        id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
        details = models.TextField()
        years_ago = models.PositiveIntegerField()
    
    >>> eventobject = Event.objects.all()
    >>> eventobject.first().id
    '3cd2b4b0c36f43488a93b3bb72029f46'

    8、

     
  • 相关阅读:
    2.6.2.MySQL主从复制的原理
    2.4.5 MySQL InnoDB重做与回滚介绍
    PRML读书笔记_绪论曲线拟合部分
    python3_字符串
    PRML读书笔记_绪论
    python3_列表、元组、集合、字典
    linux_软件安装
    shell获取帮助
    linux_查看磁盘与目录容量
    linux_压缩解压命令(zip/tar)
  • 原文地址:https://www.cnblogs.com/lxgbky/p/14903856.html
Copyright © 2011-2022 走看看