1:查询集的原生SQL
注意:像values, values_list的查询集没有query属性
queryset=Event.objects.all()
print(queryset.query)
2:OR查询
from django.db.modelsimport Q
第一种:queryset_1 | queryset_2
第二种:filter(Q(<condition_1>)|Q(<condition_2>)
3:AND查询
from django.db.modelsimport Q
第一种:filter(<condition_1>, <condition_2>)
第二种:queryset_1 & queryset_2
第三种:filter(Q(<condition_1>) & Q(<condition_2>))
4:NOT 查询
from django.db.modelsimport Q
第一种: exclude(<condition>)
第二种: filter(~Q(<condition>))
5:UNION查询 (并集)
关于MySQL union 操作可以参考:MySQL 内连接、左连接、右连接
注意:union操作只能在查询集拥有相同的字段和数据类型前提下执行,如果两个查询集的字段和数据类型不一样,union操作出现错误。你可以两个models上执行union,只要他们有相同字段或相同字段子集。
Hero.objects.all().values_list("name","gender").union(Villain.objects.all().values_list("name","gender"))
6:查询集中的部分字段
第一种: 查询集的 values 和 values_list 方法
values :查询集queryset是一个django.db.models.query.QuerySet对象, 迭代的每个元素是一个字典
values_list :查询集queryset是一个django.db.models.query.QuerySet对象, 迭代的每个元素是一个元组
第二种: only 方法,
查询集queryset是一个django.db.models.query.QuerySet对象, 迭代的每个元素是一个模型类的实例
(1):你可以访问每个实例的only方法指定的其他字段
(2):每个实例的 __dict__ 只含有 _state、id、指定的字段
(3):可以对迭代的实例进行 obj.aaa = 1000, obj.save() 操作
7:子查询
各家公司对子查询的标准不太一样,对于数据量比较大的公司一般可能不适用子查询,因为在生产中会产生查询延迟拖慢系统的或网站的整体访问效率
8:基于字段值比较标准来筛选查询集
注意:比较的两个字段的类型要求一致
from django.db.modelsimport F
from django.db.models.functionsimport Substr
(1):全字段相等 User.objects.filter(last_name=F("first_name"))
(2):首字母相同 UsersModel.objects.annotate(name=Substr("email", 1, 1), mail=Substr("username",
1, 1)).filter(name=F("mail")).values("id", "username", "email")
SQL: SELECT "circle_users"."id", "circle_users"."username", "circle_users"."email" FROM "circle_users" WHERE SUBSTRING("circle_users"."email", 1, 1) = SUBSTRING("circle_users"."username", 1, 1)
9:annotate 高级查询方法
用于分组与统计,通常与聚合函数一起使用
from django.db.modelsimport Count
(1):CircleUsersModel.objects.annotate(cnt=Count("department_chz")).values("department_chz", "cnt")
SQL:SELECT "circle_users"."department_chz", COUNT("circle_users"."department_chz") AS "cnt" FROM "circle_users" GROUP BY "circle_users"."id" (其中AS 的 `cnt` 是自定义的名字)
(2):CircleUsersModel.objects\
.values("username", "first_name")\
.annotate(name_count=Count("username"))\
.filter(name_count__gte=2)
SQL: SELECT "circle_users"."username", "circle_users"."first_name", COUNT("circle_users"."username") AS "name_count" FROM "circle_users" GROUP BY "circle_users"."username", "circle_users"."first_name" HAVING COUNT("circle_users"."username") >= 2
(3):CircleUsersModel.objects\
.annotate(name_count=Count("username")).filter(name_count__gte=2)\
.values("username", "first_name")
SQL: SELECT "circle_users"."username", "circle_users"."first_name" FROM "circle_users" GROUP BY "circle_users"."id" HAVING COUNT("circle_users"."username") >= 2
10:aggregate 聚合函数
注意: 改方法返回的不再是 django.db.models.query.QuerySet 对象, 而是一个字典;如果我要对 QerySet 中每个元素都进行聚合计算、并且返回的仍然是 QuerySet ,那就要用到 annotate() 方法了。
from django.db.modelsimport F, Count, Q, Avg, Max, Min, Sum
result = CircleUsersModel.objects.aggregate(
mix_id=Min("id"),
max_id=Max("id"),
count=Count("id"),
avg=Avg("id")
)
result: {'mix_id': 15, 'max_id': 4175, 'count': 4159, 'avg': 2095.8946862}
原生SQL: SELECT MIN("id"), MAX("id") ,COUNT("id"), SUM("id") FROM "circle_users"
aggregate 的结果集是一个字典,所以你无法通过 result.query 来打印原生sql语句。
11:extra
有些情况下,Django的查询语法难以简单的表达复杂的 WHERE 子句,对于这种情况, Django 提供了extra()QuerySet修改机制 — 它能在QuerySet生成的SQL从句中注入新子句。更多用户可以参考其他博客
注意:为了防止SQL注入,select 和 where 中的参数在select_params 和 params 中填充
queryset = CircleUsersModel.objects\
.extra(select={"bbs": "create_time > %s"}, select_params=["2020-11-24 12:00:00"],
where=['username like %s', "id> %s"], params=["丁%", "4000"])\
.values("id", "username", "bbs")
SQL: SELECT (create_time > 2020-11-24 12:00:00) AS "bbs", "circle_users"."id", "circle_users"."username" FROM "circle_users" WHERE (username like 丁%) AND (id> 4000)
结果:<QuerySet [
{'bbs': False, 'id': 4007, 'username': '丁星平'}, {'bbs': False, 'id': 4016, 'username': '丁备'}, {'bbs': False, 'id': 4035, 'username': '丁菊花'}, {'bbs': False, 'id': 4083, 'username': '丁楠'}, {'bbs': False, 'id': 4100, 'username': '丁君'}, {'bbs': False, 'id': 4101, 'username': '丁君'}, {'bbs': False, 'id': 4125, 'username': '丁锦如'}
]>
12:查找具有重复字段值的列 (其实就是分组与过滤)
duplicates = User.objects.values( 'first_name' )\
.annotate(name_count=Count('first_name'))
.filter(name_count__gt=1)
13:从查询集中找到独一无二的字段值 (同上)
distinct = User.objects.values('first_name').annotate(name_count=Count('first_name')).filter(name_count=1)
records = User.objects.filter(first_name__in=[item['first_name'] for item in distinct])
这个和 User.objects.distinct("first_name").all() 不同, User.objects.distinct("first_name").all() 会获取遇到的不同的first_name时的第一条记录。(注意部分数据库如MySQL,distinct用法是 User.objects.value("first_name").distinct())
14:Q的复杂查询
前面我们使用Q 对象来做 OR 、 AND 和 NOT 运算。Q 对象给你在where查询上绝对的控制权。
queryset = User.objects.filter( Q(first_name__startswith='R') & ~Q(last_name__startswith='Z'))
queryset = User.objects.filter( Q(first_name__startswith='R') & Q(last_name__startswith='D'))
15:一次创建多个对象
Category.objects.bulk_create([
Category(name="God"),
Category(name="Demi God"),
Category(name="Mortal")
])
16:复制一个现有的模型对象
Hero.objects.all().count() => 4
hero = Hero.objects.first()
hero.pk = None
hero.save()
Hero.objects.all().count() => 5
17:model signals
Django 提供了用于模型对象创建和删除周期的信号钩子。这些Django提供的信号是:
pre_init、post_init、pre_save、post_save、pre_delete、post_delete
在这其中最常用的信号是 pre_save 和 post_save 。我们来仔细看看他们
信号 vs 重写.save()
既然信号和重写 .save 有类似的作用,用哪一个是一个时常困惑的问题。这里给出了何时需要用哪一个。
如果你想其他人,如第三方应用,重写或定制对象的 save 行为,你应该抛出你自己singnals。
如果你想要介入一个你无权控制更改的应用中的 save 行为,你应该使用 post_save 或 pre_save 钩子信号。
如果你想定制化你自己的应用的 save 行为,你可以重写 save 方法。
18:不区分大小写的方式排序查询集
第一种:
from django.db.models.functions import Lower
User.objects.all().order_by(Lower('username')).values_list('username',flat=True)
第二种:
User.objects.annotate(uname=Lower('username')).order_by('uname').values_list('username',flat=True)
19:转化已有的数据表到Django模型
python manage.py inspectdb > models.py
20:使用Django的slug字段提高代码可读性
slug 是url的一部分,它以用户可读的形式标识一个网页中的特殊页面。为了能让它工作,Django 为我们提供了slugfield字段。可以和下面一样使用它。我们已经有一个模型 Article ,我们要添加一个slugfield使其具有有用户可读性。
from django.utils.text import slugify
class Article(models.Model):
headline = models.CharField(max_length=100)
......
slug = models.SlugField(unique=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.headline)
super(Article, self).save(*args, **kwargs)
>>> u1 = User.objects.get(id=1)
>>> from datetime import date
>>> a1 = Article.objects.create(headline="todays market report", pub_date=date(2018, 3, 6), reporter=u1)
>>> a1.save() // slug here is auto-generated, we haven't created it in the above create method.
>>> a1.slug 'todays-market-report'
Slug字段如此有用是因为:
它是人性化的(如/blog/1 而不是/1/)。
在标题,头部和url中创建一致性是一种不错的SEO。
21:ORM 各种条件查询关键字
注意:必须是model字段名后面紧跟着二个下划线
__exact 精确等于 like ‘aaa’
__iexact 精确等于 忽略大小写 ilike ‘aaa’
__contains 包含 like ‘%aaa%’
__icontains 包含 忽略大小写 ilike ‘%aaa%’,但是对于sqlite来说,contains的作用效果等同于icontains
__gt 大于
__gte 大于等于
__lt 小于
__lte 小于等于
__in 存在于一个list范围内
__startswith 以…开头
__istartswith 以…开头 忽略大小写
__endswith 以…结尾
__iendswith 以…结尾,忽略大小写
__range 在…范围内
__year 日期字段的年份
__month 日期字段的月份
__day 日期字段的日
__isnull=True/False
网友评论