Django Query
Making Qeries
一旦创建了数据模型,Django就会自动为您提供一个数据库抽象API,允许您创建、检索、更新和删除对象。本文档解释了如何使用这个API。
The models
一个class代表一个数据库中的table
from django.db import models
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def __str__(self):
return self.name
class Author(models.Model):
name = models.CharField(max_length=200)
email = models.EmailField()
def __str__(self):
return self.name
class Entry(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
headline = models.CharField(max_length=255)
body_text = models.TextField()
pub_date = models.DateField()
mod_date = models.DateField()
authors = models.ManyToManyField(Author)
n_comments = models.IntegerField()
n_pingbacks = models.IntegerField()
rating = models.IntegerField()
def __str__(self):
return self.headline
Creating objects
insert a record in table
>>> from blog.models import Blog
>>> b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
>>> b.save()
Saving changes to objects
update a record in table
>>> b5.name = 'New name'
>>> b5.save()
Saving ForeignKey and ManyToManyField fields
保存一对多关系和多对多关系
# The ForeignKey
>>> from blog.models import Blog, Entry
>>> entry = Entry.objects.get(pk=1)
>>> cheese_blog = Blog.objects.get(name="Cheddar Talk")
>>> entry.blog = cheese_blog
>>> entry.save()
# The ManyToManyField
>>> from blog.models import Author
>>> joe = Author.objects.create(name="Joe")
>>> entry.authors.add(joe,...)
Retrieving objects
检查对象请通过模型类上的Manager构造一个QuerySet。
每个模型至少拥有一个Manager管理器,默认为objects,可以通过类来获取它。
>>> Blog.objects
<django.db.models.manager.Manager object at ...>
>>> b = Blog(name='Foo', tagline='Bar')
>>> b.objects
Traceback:
...
AttributeError: "Manager isn't accessible via Blog instances."
注:管理器只能通过模型类访问,而不是从模型实例访问,以强制“表级”操作和“记录级”操作之间的分离
管理器是模型的查询集的主要来源。
Retrieving all objects
获取所有对象
>>> all_entries = Entry.objects.all()
Retrieving specific objects with filters
获取过滤后的对象
Entry.objects.filter(pub_date__year=2006)
# is the same as
Entry.objects.all().filter(pub_date__year=2006)
Chaining filters
提炼一个QuerySet的结果本身就是一个QuerySet,所以可以将提炼链接在一起。
>>> Entry.objects.filter(
... headline__startswith='What'
... ).exclude(
... pub_date__gte=datetime.date.today()
... ).filter(
... pub_date__gte=datetime.date(2005, 1, 30)
... )
Filtered QuerySets are unique
每次提炼一次QuerySet,就会得到一个全新的QeurySet,与之前的QeurySet没有任何联系
QuerySets are lazy
提炼QuerySet是惰性查询,本身不涉及到任何数据库查询,所以可以随意拼接它
Retrieving a single object with get()
filter()将得到一个QuerySet,如果您想得到一个单独的实体对象 可以使用get()
>>> one_entry = Entry.objects.get(pk=1)
Retrieving QuerySets with exclude
排除条件
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')
# transform SQL
SELECT ... WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')
Limiting QuerySets
截取QuerySet,与python list类似 不支持使用负数
>>> Entry.objects.all()[:5]
>>> Entry.objects.all()[5:10]
>>> Entry.objects.all()[:10:2]
to get a single object
>>> Entry.objects.order_by('headline')[0]
# is the same as
>>> Entry.objects.order_by('headline')[0:1].get()
Field lookups
字段查找是指定SQL WHERE子句的核心内容的方式。它们被指定为QuerySet方法filter()、exclude()和get()的关键字参数。
基本查找关键字参数的形式为field__lookuptype=value。(这是一个双下划线)。
__lte
>>> Entry.objects.filter(pub_date__lte='2006-01-01')
# transform SQL
SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01'
_id
查找中指定的字段必须是模型字段的名称。但是有一个例外,对于ForeignKey,您可以指定以_id为后缀的字段名。在这种情况下,值参数应该包含外部模型主键的原始值。
>>> Entry.objects.filter(blog_id=4)
exact 默认的,可以忽略
>>> Blog.objects.get(id__exact=14)
# is the same as
>>> Blog.objects.get(id=14)
# transform SQL
SELECT ... WHERE id = 14;
iexact 与exact类似,不区分大小写
contains
Entry.objects.get(headline__contains='Lennon')
# transform SQL
SELECT ... WHERE headline LIKE '%Lennon%';
Lookups that span relationships
跨域查找
要跨越关系,只需跨模型使用相关字段的字段名(用双下划线分隔),直到到达您想要的字段为止
>>> Entry.objects.filter(blog__name='Beatles Blog')
它也可以反向工作。要引用“反向”关系,只需使用模型的小写名称。
>>> Blog.objects.filter(entry__headline__contains='Lennon')
spanning multi-value relationships
跨越多值关系
Blog.objects.filter(entry__headline__contains='Lennon', entry__pub_date__year=2008)
# is the same as
Blog.objects.filter(entry__headline__contains='Lennon').filter(entry__pub_date__year=2008)
Filters can reference fields on the model
过滤器可以引用模型上的字段 F表达式
>>> from django.db.models import F
>>> Entry.objects.filter(n_comments__gt=F('n_pingbacks'))
>>> Entry.objects.filter(n_comments__gt=F('n_pingbacks') * 2)
>>> Entry.objects.filter(rating__lt=F('n_comments') + F('n_pingbacks'))
>>> Entry.objects.filter(authors__name=F('blog__name')) #跨域
>>> from datetime import timedelta
>>> Entry.objects.filter(mod_date__gt=F('pub_date') + timedelta(days=3))
The pk lookup shortcut
为了方便起见,Django提供了一个pk查找快捷方式,它表示“主键”。
>>> Blog.objects.get(id__exact=14) # Explicit form
>>> Blog.objects.get(id=14) # __exact is implied
>>> Blog.objects.get(pk=14) # pk implies id__exact
Caching and QuerySets
每个QuerySet包含一个缓存,以最小化数据库访问。了解它的工作原理将使您能够编写最高效的代码。
在新创建的QuerySet中,缓存是空的。当第一次计算QuerySet时(因此发生了数据库查询),Django将查询结果保存在QuerySet的缓存中,并返回显式请求的结果(例如,下一个元素,如果迭代QuerySet的话)。QuerySet的后续评估重用缓存的结果。
请记住这种缓存行为,因为如果您没有正确使用queryset,它可能会影响您。例如,下面将创建两个查询集,计算它们,并将它们丢弃:
>>> print([e.headline for e in Entry.objects.all()])
>>> print([e.pub_date for e in Entry.objects.all()])
这意味着相同的数据库查询将被执行两次,从而使数据库负载加倍。另外,两个列表可能不包含相同的数据库记录,因为在两个请求之间的瞬间,可能添加或删除了一个条目。
避免这个问题,只需保存QuerySet并重用它
>>> queryset = Entry.objects.all()
>>> print([p.headline for p in queryset]) # Evaluate the query set.
>>> print([p.pub_date for p in queryset]) # Re-use the cache from the evaluation.
When QuerySets are not cached
查询集并不总是缓存它们的结果。当只计算queryset的一部分时,会检查缓存,但是如果它没有被填充,那么后续查询返回的项就不会被缓存。具体来说,这意味着使用数组切片或索引限制queryset不会填充缓存。
>>> queryset = Entry.objects.all()
>>> print(queryset[5]) # Queries the database
>>> print(queryset[5]) # Queries the database again
但是,如果已经计算了整个queryset的值,那么缓存将被检查:
>>> queryset = Entry.objects.all()
>>> [entry for entry in queryset] # Queries the database
>>> print(queryset[5]) # Uses cache
>>> print(queryset[5]) # Uses cache
other methods to populate the cache
>>> [entry for entry in queryset]
>>> bool(queryset)
>>> entry in queryset
>>> list(queryset)
简单地打印queryset不会填充缓存。这是因为对__repr__()的调用只返回整个queryset的一部分。
Complex lookups with Q objects
复杂查询使用Q方法
Q对象(django.db.models.Q)是用来封装关键字参数集合的对象。这些关键字参数在上面的“字段查找”中指定。
from django.db.models import Q
Q(question__startswith='What')
Q对象可以使用&和|运算符组合。当对两个Q对象使用运算符时,它会生成一个新的Q对象。
例如,该语句生成一个Q对象,该对象表示两个“question__startswith”查询的“或”
Q(question__startswith='Who') | Q(question__startswith='What')
通过将Q对象与&和|运算符组合起来并使用括号分组,您可以组合任意复杂的语句。同样,可以使用~操作符来否定Q对象,允许组合查找,将普通查询和否定(非)查询结合起来
Q(question__startswith='Who') | ~Q(pub_date__year=2005)
每个获取关键字参数的查找函数(例如filter()、exclude()、get())也可以作为位置(非命名)参数传递一个或多个Q对象。如果您为查找函数提供多个Q对象参数,这些参数将“AND”ed一起使用。例如:
Poll.objects.get(
Q(question__startswith='Who'),
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)
# transform SQL
SELECT * from polls WHERE question LIKE 'Who%'
AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')
查找函数可以混合使用Q对象和关键字参数。为查找函数提供的所有参数(无论是关键字参数还是Q对象)都是“ed”在一起的。但是,如果提供了Q对象,那么它必须先于任何关键字参数的定义。
# INVALID QUERY. Q() is must be before keyword arguments
Poll.objects.get(
question__startswith='Who',
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)
Comparing objects
要比较两个模型实例,只需使用标准的Python比较运算符:==。在幕后,比较两个模型的主要关键值。
>>> some_entry == other_entry
>>> some_entry.id == other_entry.id
Deleting objects
>>> e.delete()
>>> Entry.objects.filter(pub_date__year=2005).delete()
(5, {'webapp.Entry': 5})
当Django删除一个对象时,默认情况下它会模拟SQL约束在DELETE CASCADE上的行为——换句话说,任何有外键指向要删除的对象的对象都将被删除。这个级联行为可以通过对ForeignKey的on_delete参数进行定制。
b = Blog.objects.get(pk=1)
# This will delete the Blog and all of its Entry objects.
b.delete()
注意,delete()是唯一没有在管理器本身上公开的QuerySet方法。这是一种安全机制,可以防止您意外地请求Entry.objects.delete()和删除所有条目。如果您确实想删除所有对象,那么您必须显式地请求完整的查询集:
Entry.objects.all().delete()
Copying model instances
blog = Blog(name='My blog', tagline='Blogging is easy')
blog.save() # blog.pk == 1
blog.pk = None
blog.save() # blog.pk == 2
如果使用继承,事情会变得更加复杂。考虑博客的一个子类
class ThemeBlog(Blog):
theme = models.CharField(max_length=200)
django_blog = ThemeBlog(name='Django', tagline='Django is easy', theme='python')
django_blog.save() # django_blog.pk == 3
django_blog.pk = None
django_blog.id = None
django_blog.save() # django_blog.pk == 4
这个过程不会复制不属于模型数据库表的关系。例如,Entry有很多个要编写的字段。复制条目后,必须为新Entry设置多对多关系:
entry = Entry.objects.all()[0] # some previous entry
old_authors = entry.authors.all()
entry.pk = None
entry.save()
entry.authors.set(old_authors)
对于一个OneToOneField,必须复制相关对象并将其分配给新对象的字段,以避免违反一对一唯一约束。例如,假设Entry已经复制到上面:
detail = EntryDetail.objects.all()[0]
detail.pk = None
detail.entry = entry
detail.save()
Updating multiple objects at once
有时,您希望为QuerySet中的所有对象将字段设置为特定值。您可以使用update()方法来做到这一点。
# Update all the headlines with pub_date in 2007.
Entry.objects.filter(pub_date__year=2007).update(headline='Everything is the same')
>>> Entry.objects.all().update(n_pingbacks=F('n_pingbacks') + 1)
注:update操作中的F()不能进行join连接 否则会报错FieldError
Related objects
当建立了一个关系在模型中(ForeignKey,OneToOneField,ManyToManyField),该模型的实例将具有方便的API来访问相关对象。
>>> e = Entry.objects.get(id=2)
>>> e.blog # Returns the related Blog object.
>>> e = Entry.objects.get(id=2)
>>> e.blog = some_blog
>>> e.save()
>>> e = Entry.objects.get(id=2)
>>> e.blog = None
>>> e.save() # "UPDATE blog_entry SET blog_id = NULL ...;"
Following relationships “backward”
如果模型有一个ForeignKey,那么外键模型的实例将访问返回第一个模型的所有实例的管理器。默认情况下,该管理器名为FOO_set,其中FOO是源模型名,小写。此管理器返回QuerySets,可以按照上面“检索对象”一节的描述对其进行过滤和操作。
>>> b = Blog.objects.get(id=1)
>>> b.entry_set.all() # Returns all Entry objects related to Blog.
# b.entry_set is a Manager that returns QuerySets.
>>> b.entry_set.filter(headline__contains='Lennon')
>>> b.entry_set.count()
通过在ForeignKey定义中设置related_name参数,可以覆盖FOO_set名称。
Using a custom reverse manager
默认情况下,用于反向关系的RelatedManager是该模型的默认管理器的子类。如果您想为给定的查询指定不同的管理器,可以使用以下语法
from django.db import models
class Entry(models.Model):
#...
objects = models.Manager() # Default Manager
entries = EntryManager() # Custom Manager
b = Blog.objects.get(id=1)
b.entry_set(manager='entries').all()
如果EntryManager在其get_queryset()方法中执行默认过滤,则该过滤将应用于all()调用。
当然,指定一个定制的反向管理器还可以调用它的定制方法:
b.entry_set(manager='entries').is_published()
Additional methods to handle related objects
add(obj1, obj2, ...) 添加模型实例
create(**kwargs) 创建一个新的模型对象
remove(obj1, obj2, ...) 从相关对象集中删除指定的模型对象
clear() 清空所有对象
set(objs) 替换相关对象集。
Many-to-many relationships
多对多关系的两端都可以自动访问另一端的API。该API的工作方式类似于上面的“向后”一对多关系。
一个区别是属性命名:定义ManyToManyField的模型使用的是该字段本身的属性名,而“反转”模型使用的是原始模型的小写模型名加上“_set”(就像反向一对多关系一样)。
e = Entry.objects.get(id=3)
e.authors.all() # Returns all Author objects for this Entry.
e.authors.count()
e.authors.filter(name__contains='John')
a = Author.objects.get(id=5)
a.entry_set.all() # Returns all Entry objects for this Author.
与ForeignKey一样,ManyToManyField可以指定related_name。在上面的例子中,如果条目中的ManyToManyField指定了related_name='entries',那么每个Author实例都有一个entries属性,而不是entry_set。
与一对多关系的另一个区别是,除了模型实例之外,多对多关系上的add()、set()和remove()方法还接受主键值。例如,如果e1和e2是条目实例,那么这些set()调用的工作方式相同:
a = Author.objects.get(id=5)
a.entry_set.set([e1, e2])
a.entry_set.set([e1.pk, e2.pk])
One-to-one relationships
一对一关系非常类似于多对一关系。如果您在模型上定义了一个OneToOneField,该模型的实例将通过模型的简单属性访问相关对象。
class EntryDetail(models.Model):
entry = models.OneToOneField(Entry, on_delete=models.CASCADE)
details = models.TextField()
ed = EntryDetail.objects.get(id=2)
ed.entry # Returns the related Entry object.
区别在于“反向”查询。一对一关系中的相关模型也可以访问Manager对象,但该管理器表示单个对象,而不是对象的集合:
e = Entry.objects.get(id=2)
e.entrydetail # returns the related EntryDetail object
如果没有给这个关系分配对象,Django将会引发一个DoesNotExist异常。
实例可以以与分配正向关系相同的方式分配反向关系
e.entrydetail = ed
Performing raw SQL queries
class Person(models.Model):
first_name = models.CharField(...)
last_name = models.CharField(...)
birth_date = models.DateField(...)
>>> for p in Person.objects.raw('SELECT * FROM myapp_person'):
... print(p)
John Smith
Jane Jones
raw()自动将查询中的字段映射到模型中的字段。与查询字段的顺序无关,下列的例子相同
>>> Person.objects.raw('SELECT id, first_name, last_name, birth_date FROM myapp_person')
...
>>> Person.objects.raw('SELECT last_name, birth_date, first_name, id FROM myapp_person')
...
匹配是通过名称来完成的。这意味着您可以使用SQL AS子句将查询中的字段映射到建模字段。所以如果你有另外一个表里面有Person数据,你可以很容易地把它映射到Person实例
>>> Person.objects.raw('''SELECT first AS first_name,
... last AS last_name,
... bd AS birth_date,
... pk AS id,
... FROM some_other_table''')
raw()支持索引,所以如果你只需要第一个结果,你可以写:
>>> first_person = Person.objects.raw('SELECT * FROM myapp_person')[0]
然而,索引和切片并不是在数据库级别执行的。如果您的数据库中有大量Person对象,那么在SQL级别上限制查询会更有效:
>>> first_person = Person.objects.raw('SELECT * FROM myapp_person LIMIT 1')[0]
# Deferring model fields
这个查询返回的Person对象将是deferred model实例(参见defer())。这意味着查询中省略的字段将根据需要加载。例如
您还可以执行包含模型中未定义的字段的查询。例如,我们可以使用PostgreSQL 's age()函数得到数据库计算出的年龄人员列表:
>>> people = Person.objects.raw('SELECT *, age(birth_date) AS age FROM myapp_person')
>>> for p in people:
... print("%s is %s." % (p.first_name, p.age))
John is 37.
Jane is 42.
#Passing parameters into raw()
>>> lname = 'Doe'
>>> Person.objects.raw('SELECT * FROM myapp_person WHERE last_name = %s', [lname])
* 不要对原始查询使用字符串格式,也不要在SQL字符串中引用占位符!这有sql注入风险
Executing custom SQL directly
有时候,甚至Manager.raw()也不够:您可能需要执行不能清晰映射到模型的查询,或者直接执行更新、插入或删除查询。
在这些情况下,您总是可以直接访问数据库,完全围绕模型层路由。
对象django.db。连接表示默认的数据库连接。要使用数据库连接,请调用connection.cursor()来获得一个游标对象。然后,叫游标。执行(sql, [params])以执行sql和cursor.fetchone()或cursor.fetchall()以返回结果行。
如果您在MySQL上执行查询,请注意MySQL的静默类型强制可能会在混合类型时导致意外结果。如果查询字符串类型列,但使用整数值,MySQL将强制表中所有值的类型为整数,然后再执行比较。例如,如果表中包含值“abc”、“def”,并且查询mycolumn=0的位置,那么这两行都将匹配。为了防止这种情况,在使用查询中的值之前执行正确的类型转换。
Django Query的更多相关文章
- Django – query not equal
The simpliest way to retrieve data from tables is take them all. To do this, you can write: 1 all_e ...
- python3环境搭建(uWSGI+django+nginx+python+MySQL)
1.系统环境,必要知识 #cat /etc/redhat-release CentOS Linux release (Core) #uname -r -.el7.x86_64 暂时关闭防护墙,关闭se ...
- Django调试models输出的SQL语句
django1.3在shell下,调试models变得更为简单了,不用像之前的版本,手工去调用django query,才能打印出之前的代码是执行的什么SQL语句. 1.3开始只需在settings. ...
- Django 调试models 输出的SQL语句 定位查看结果
django 调试models变得更为简单了,不用像之前的版本, 手工去调用django query, 才能打印出之前的代码是执行的什么SQL语句. 1.3开始只需在settings.py里,配置如下 ...
- python中的 __repr__和__str__
__repr__,被内置函数repr用于把一个对象用"官方"的字符串形式表示出来(终端友好) 1.值传给eval()来返回一个对象的字符串表示形式 2.否则返回一个尖括 ...
- python代码的那些设计
一.Django的ORM 1.类QuerySet (django) :QuerySet 可以被构造,过滤,切片,做为参数传递,这些行为都不会对数据库进行操作.只要你查询的时候才真正的操作数据库. 2. ...
- 第6模块 web框架口述题
状态码如200 OK,以3位数字和原因 成.数字中的 一位指定了响应 别,后两位无分 .响应 别有以下5种. 重定向:客户端像服务器端发送请求,服务器告诉客户端你去重定向(状态码302,响应头loca ...
- 测试同学动手搭个简易web开发项目
技术栈 node.js, vue.js, axios, python, django, orm, restful api, djangorestframework, mysql, nginx, jen ...
- get_or_create update_or_create
django/query.py at master · django/django https://github.com/django/django/blob/master/django/db/mod ...
随机推荐
- 动态修改datagrid中的numberbox的最大值和最小值
注意datagrid使用的触发函数是: onBeginEdit,只有在这个触发条件下,editor才真正初始化完成,不然没法动态修改numberbox中的最大最小值. 示例代码:(注意这一块:onBe ...
- redis centos7
官网下载tar包 make 修改conf 修改 启动脚本 utils/redis_init_script 开放端口6379
- java 蓝桥杯算法提高 矩阵乘法
思路:根据提示的内容,我们可以得到c[i][j] += a[i][k]*b[k][j],k>=0&&k<s PS:这道题本身不难,但是当我定义A[m][s] B[s][n] ...
- 设置WebBrowser内核渲染模式
前不久开发一个项目,是采用WebBrowser作为外壳,加载网页,由于网页是采用html5来进行开发的,当通过WebBrowser加载网页后,html5中的特性 都无法正常显示,而通过ie浏览器打开时 ...
- 01-MySQL优化大的思路
首先不是看它的表结构等等.从整体上去观察,不断去看它的状态.这个状态往往不是一两个小时可以看出来的,得写一个脚本,观察它的24小时的周期性变化,不断刷新它的脚本,观察它的Status.主要是看它有没有 ...
- java动态规划问题
这里是简单的动态规划问题.其实,如果我们学过数据结构,应该就接触过动态规划问题,当时一直没有反应过来.我们求最小生成树用的是贪婪算法.而求最短路径就是动态规划.从一个点出发,到另外每个点的最短距离.在 ...
- 10-stack
c++ stl栈stack介绍 C++ Stack(堆栈) 是一个容器类的改编,为程序员提供了堆栈的全部功能,——也就是说实现了一个先进后出(FILO)的数据结构. c++ stl栈stack的头文件 ...
- cacti-不出图形,cacti.log中出“ERROR: SQL Assoc Failed!
[root@CactiEZ log]# tail cacti.log 2016年04月06日 14:53:16 PM - CMDPHP: Poller[0] ERROR: SQL Cell Faile ...
- linux c MQTT客户端实现
linux c MQTT客户端实现 摘自:https://www.jianshu.com/p/d309de966379 一.前言:mqtt协议是轻量级的消息订阅和发布(publish/subscrib ...
- Spring Boot☞ 使用freemarker模板引擎渲染web视图
效果图 代码 package com.wls.integrateplugs.hello.controller; /** * Created by wls on 2017/8/24. */ import ...