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)

django queryset用法总结二

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

   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 一定是被查询字段的非计算列

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)

 

1、

 

 

1、

 

 

1、

 

 

django queryset用法总结二

上一篇:08.Redis_新功能


下一篇:聚合函数