Django之ORM操作
此篇依赖于上一篇:Django之模型注册
我们在models.py中定义的表结构,在admin.py中将它们注册进去了,现在我们登陆django admin界面就会看到我们注册的所有表。
数据如下:
现在我们来拿Blog表,进行增删改查操作,它总共两个字段name,tagline。
进入项目目录下,执行:
增删改
增加记录
python manager.py shell from orm.models import Blog b = Blog(name="javaScript",tagline="java model") b.save() 或 Blog(name="Windows",tagline="Windows model").save() 或 Blog.objects.create(name="Onesen",tagline="Onesen Ui")
删除记录
Blog.objects.filter(name="Linux").delete()
修改记录
Blog.objects.filter(name="Onesen").update(tagline="TwoSen") Entry.objects.filter(pub_date__year=2007).update(headline='Everything is the same') # 将原有数据批量自增 Entry.objects.all().update(n_pingbacks=F('n_pingbacks') + 1)
关联:
以Blog表和Entry表的关联为例
ForeignKey的关联修改
# Blog表是Entry表的外键 from orm.models import Entry # 找出一条Blog记录 cheese_blog = Blog.objects.get(name="Windows") # 找出一条Entry记录 entry = Entry.objects.get(pk=1) # 将Entry表的blog与查询到的blog关联 entry.blog = cheese_blog # 保存Entry设置 entry.save()
ManyToManyField关联修改
Entry表中authors = models.ManyToManyField(Author)
以Author表和Entry表的关联人例,现在给Entry表的authors字段关联多个Author
关联前
开始关联
# 从Author表中选择出3个对象 from orm.models import Author author1 = Author.objects.get(pk=1) author2 = Author.objects.get(pk=2) author3 = Author.objects.get(pk=3) # 从Entry表中选择出一个对象 from orm.models import Entry entry = Entry.objects.get(pk=1) # 将从Author表选择出的3个对象关联到Entry表选择出的1个对象中 entry.authors.add(author1,author2,author3)
关联后
普通查询
除了可以通过python manager.py shell来查询数据以外,还可以通过pycharm来查询数据。
例如:
#!/usr/bin/env python # _*_ coding:utf-8 _*_ import os os.environ['DJANGO_SETTINGS_MODULE'] = 'Blog.settings' import django django.setup() from orm import models auth = models.Author.objects.get(pk=1) print auth
单表查询
#!/usr/bin/env python # _*_ coding:utf-8 _*_ import os os.environ['DJANGO_SETTINGS_MODULE'] = 'Blog.settings' import django django.setup() import datetime from orm import models # 单条查询用get,不可返回多条数据 models.Entry.objects.get(pk=1) models.Entry.objects.get(headline__exact='technology') models.Entry.objects.get(headline__iexact='technology') # 大小写不敏感 models.Entry.objects.get(headline__contains='nology') models.Entry.objects.get(headline__icontains='nology') # 多条查询用filter models.Entry.objects.filter(pub_date__year=2017) models.Entry.objects.all().filter(pub_date__year=2017) models.Entry.objects.filter(pub_date__gt='2017-03-30') # 排除用exclude datas = models.Entry.objects.filter( headline__startswith=u"文学" ).exclude( pub_date__gt=datetime.date.today() ) # 查询出固定的条数用切片 models.Entry.objects.all()[:2] # 排序操作用order_by models.Entry.objects.order_by('pub_date')[0] # 查询所有用all models.Entry.objects.all()
关联查询
不同表之间关联查询
#!/usr/bin/env python # _*_ coding:utf-8 _*_ import os os.environ['DJANGO_SETTINGS_MODULE'] = 'Blog.settings' import django django.setup() import datetime from orm import models # 与entry.headline模糊匹配tech的所有记录有关联的Blog表的所有记录 models.Blog.objects.filter(entry__headline__contains='tech') # 与Blog.name精确匹配Windows的所有记录有关联的Entry表的所有记录 models.Entry.objects.filter(blog__name__exact='Windows')
同一张表的不同字段的操作
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'Blog.settings'
import django
django.setup()
from orm import models
from django.db.models import F
# 查询Entry表的所有记录,条件是n_pingbacks值大于n_comments
models.Entry.objects.filter(n_pingbacks__gt=F('n_comments'))
# 查询Entry表的所有记录,条件是n_pingbacks值大于rating*1.5
models.Entry.objects.filter(n_pingbacks__gt=F('rating')*1.5)
from datetime import timedelta
# 查询Entry表的所有记录,条件是mod_date大于pub_date加3天
models.Entry.objects.filter(mod_date__gt=F('pub_date') + timedelta(days=3))
Caching and QuerySets
每个QuerySet包含一个Cache来最小化数据库访问。明白它是如何工作的将有利于你写出高效的代码。
当产生一个新的QuerySet时,它的Cache是空的。当第一次操作QuerySet时,发生了数据库查询,Django在返回精确请求结果的同时将查询结果保存在QuerySet的Cache中,随后对QuerySet的访问将重用Cache中的结果
# 一次数据库查询,随后都是Cache访问 queryset = Entry.objects.all() # 产生空的QuerySet [entry for entry in queryset] # Queries the database,对QuerySet做了完全评估,此时QuerySet会Cache结果集 print queryset[5] # Uses cache print queryset[5] # Uses cache # 此时会产生一次数据库查询,一次利用Cache queryset = Entry.objects.all() print([p.headline for p in queryset]) # Queries the database,对QuerySet做了完全评估,此时QuerySet会Cache结果集 print([p.headline for p in queryset]) # 两次数据库查询 queryset = Entry.objects.all() print queryset[5] # Queries the database,对QuerySet做了部分评估,此时QuerySet不Cache结果集 print queryset[5] # Queries the database again # 此时将会产生两次数据库查询 print([e.headline for e in Entry.objects.all()]) print([e.headline for e in Entry.objects.all()])
复杂查询
Q对象可用来封装查询关键字,需要从django.db.models中导入Q方法
# Q实现一个简单的LIKE查询 from django.db.models import Q Q(question__startswith='What') # 使用&或|来将两个Q对象组合成一个新的Q对象 Q(question__startswith='Who') | Q(question__startswith='What') 这个操作类似以下WHERE语句 WHERE question LIKE 'Who%' OR question LIKE 'What%' # Q对象使用~来执行一个否操作 Q(question__startswith='Who') | ~Q(pub_date__year=2005) # 如果同时罗列出多个Q查询,则它们会被AND到一起 Poll.objects.get( Q(question__startswith='Who'), Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)) ) 换成SQL语句则为: SELECT * from polls WHERE question LIKE 'Who%' AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06') # 当Q对象和关键字参数结合使用的时候,Q对象必须放在关键字前面 如,以下语句是合法的 Poll.objects.get( Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)), question__startswith='Who') 否则不合法 Poll.objects.get( question__startswith='Who', Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))
聚合查询
#!/usr/bin/env python # _*_ coding:utf-8 _*_ import os os.environ['DJANGO_SETTINGS_MODULE'] = 'Blog.settings' import django django.setup() from orm import models # 总计 models.Entry.objects.count() models.Entry.objects.filter(headline__startswith='tech').count() # 平均值 from django.db.models import Avg models.Entry.objects.aggregate(Avg('rating')) models.Entry.objects.all().aggregate(Avg('rating')) # 最大值 from django.db.models import Max models.Entry.objects.aggregate(Max('rating')) models.Entry.objects.all().aggregate(Max('rating'))
更多聚合查询的例子:https://docs.djangoproject.com/en/1.9/topics/db/aggregation/
用户认证
from django.contrib.auth import authenticate user = authenticate(username='john', password='secret') if user is not None: # the password verified for the user if user.is_active: print("User is valid, active and authenticated") else: print("The password is valid, but the account has been disabled!") else: # the authentication system was unable to verify the username and password print("The username and password were incorrect.")
用户退出
from django.contrib.auth import logout def logout_view(request): logout(request) # Redirect to a success page.