2016-04-04 初稿
2016-06-30 更新内容
限制普通字段的选择范围
choices
,value-text,
显示get_foo_display()
模型继承
多重继承主要用于mix-in
类
多表继承时使用parent_link=True
显示指定OneToOne字段
与尚未定义的模型关联使用模型名字(字符串)而非本身(类)
关联自己使用self
related_name
relate_query_name
外键关联到特定字段
to_field
限制外键的选择范围(可以是一个字典、一个Q 对象或者一个返回字典或Q对象的可调用对象)
limit_choices_to
外键关联对象删除行为
on_delete
1.8以后保存模型时,未保存的外键对象将被忽略,除非设置allow_unsaved_instance_assignment=True
关联自身的多对多关系默认对称,取消对称设置symmetrical=False
ImageField
中的height_field
和width_field
是用来存储存入图片的高度和宽度值的
##执行查询
可自定义查询(高级查找)
exclude
多条件查询时是用or关系而不是and关系
F()
用于模型内部字段间的比较支持加法、减法、乘法、除法、取模以及幂计算等算术操作
支持.bitand() 和.bitor()位操作,update()
也可以使用F()
但有限制(在update 中你不可以使用F() 对象引入join —— 你只可以引用正在更新的模型的字段)
查询集缓存
当只对查询集的部分进行求值时会检查缓存, 但是如果这个部分不在缓存中,那么接下来查询返回的记录都将不会被缓存。
>>> 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.
>>> queryset = Entry.objects.all()
>>> print queryset[5] # Queries the database
>>> print queryset[5] # Queries the database again
>>> queryset = Entry.objects.all()
>>> [entry for entry in queryset] # Queries the database
>>> print queryset[5] # Uses cache
>>> print queryset[5] # Uses cache
Q()
可使用Q对象进行复杂查询
判断两相模型实例是否相同,直接使用==
比较即可
默认批量删除对象时不会调用实例的delete
方法
拷贝实例,把pk
设置为None
再save
即可(如果是继承的,则pk
和id
都需要设置为None
)
update()
方法也不会调用模型的save()
方法,不会发出pre_save
和post_save
信号,字段的auto_now
也不会起作用
一对多关联对象访问会缓存
>>> e = Entry.objects.get(id=2)
>>> print(e.blog) # Hits the database to retrieve the associated Blog.
>>> print(e.blog) # Doesn't hit the database; uses cached version.
自定义反向管理器1.7+
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()
一次创建多条数据(只有一条sql)
bulk_create
根据提供的一组pk
查询出所有对应的对象
in_bulk
在查作者列表时要查每个作者有几篇博文
>>> from django.db.models import Count
>>> authors = Author.object.all().annotate(Count('blog'))
# authors[0]作者的博文数
>>> authors[0].blog__count
3
# 或
>>> authors = Author.object.all().annotate(number_of_blog=Count('blog'))
>>> authors[0].number_of_blog
3
算出所有作者的年龄总合(不需要其它数据)
>>> ageAuthor.objects.all().aggregate(Sum('age'))
{'age__sum': 26}
annotate
和aggregate
都可写入多个注解表达式
annotate
和aggregate
可聚合关联对象
对注解进行过滤
# 查询出作者数大于1的书本
# 只有一条sql
Book.objects.annotate(num_authors=Count('authors')).filter(num_authors__gt=1)
但顺序不一样,结果也不同,如:
Publisher.objects.annotate(num_books=Count('book')).filter(book__rating__gt=3.0)
Publisher.objects.filter(book__rating__gt=3.0).annotate(num_books=Count('book'))
对注解项进行排序
Book.objects.annotate(num_authors=Count('authors')).order_by('num_authors')
values()
使用注解时要小心,如果values()
在注解之前,会对结果进行分组,注解会作用在分组上而不是整个查询集上
与默认排序交换或order_by()¶
在查询集中的order_by() 部分(或是在模型中默认定义的排序项) 会在选择输出数据时被用到,即使这些字段没有在 values() 调用中被指定。这些额外的字段可以将相似的数据行分在一起,也可以让相同的数据行相分离。在做计数时, 就会表现地格外明显:
通过例子中的方法,假设有一个这样的模型:
from django.db import models
class Item(models.Model):
name = models.CharField(max_length=10)
data = models.IntegerField()
class Meta:
ordering = ["name"]
关键的部分就是在模型默认排序项中设置的name字段。如果你想知道每个非重复的data值出现的次数,可以这样写:
# Warning: not quite correct!
Item.objects.values("data").annotate(Count("id"))
...这部分代码想通过使用它们公共的 data 值来分组 Item对象,然后在每个分组中得到 id 值的总数。但是上面那样做是行不通的。这是因为默认排序项中的 name也是一个分组项,所以这个查询会根据非重复的 (data, name) 进行分组,而这并不是你本来想要的结果。所以,你应该这样改写:
Item.objects.values("data").annotate(Count("id")).order_by()
...这样就清空了查询中的所有排序项。 你也可以在其中使用 data ,这样并不会有副作用,这是因为查询分组中只有这么一个角色了。
这个行为与查询集文档中提到的 distinct() 一样,而且生成规则也一样:一般情况下,你不想在结果中由额外的字段扮演这个角色,那就清空排序项,或是至少保证它仅能访问 values()中的字段。
http://python.usyiyi.cn/django/intro/tutorial06.html
http://python.usyiyi.cn/django/ref/templates/builtins.html
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static user_stylesheet %}" />
<link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}" />
<link rel="stylesheet" type="text/css" href="{% get_static_prefix %}pools/style.css" />
{% get_static_prefix as STATIC_PREFIX %}
<link rel="stylesheet" type="text/css" href="{{ STATIC_PREFIX }}pools/style.css" />
{% static "images/hi.jpg" as myphoto %}
<img src="{{ myphoto }}"></img>
还有get_media_prefix
从数据库中重新加载值
Model.refresh_from_db(using=None, fields=None, **kwargs)
返回模型中当前所有延迟字段的属性名称
Model.get_deferred_fields()
验证对象
字段的基本验证会最先跑,但不管前面运行是否通过,对于每个字段,如果Field.clean() 方法抛出 ValidationError,那么将不会调用该字段对应的clean_
()方法。 但是,剩余的字段的验证方法仍然会执行。
先跑form
里验证,再跑modle
验证
先跑验证器,再跑clean
先跑单个字段验证,再跑整体验证
Model.clean_field()
会覆盖Model
里所有字段的验证器,但不会对Form
里的验证器产生影响
验证模型的字段Model.clean_fields(exclude=None)
验证模型的完整性Model.clean()
验证模型的唯一性Model.validate_unique(exclude=None)
调用full_clean()
时,上面三个方法都会执行(执行顺序即上面的书写顺序),ModelForm
的is_valid()
也会执行上所有验证
Model.full_clean(exclude=None, validate_unique=True)
save()
时,full_clean()
不会被调用,如果想验证数据,可手动调用
Model.clean()
时,引发特定字段的异常
使用一个字典实例化ValidationError
即可或使用add_error(field, msg)
方法
在数据库字段值的基础上进行简单的算法操作,应该尽量使用F()
表达式,避免问题竞态条件
指定要保存的字段
如果传递给save() 的update_fields 关键字参数一个字段名称列表,那么将只有该列表中的字段会被更新。如果你想更新对象的一个或几个字段,这可能是你想要的。不让模型的所有字段都更新将会带来一些轻微的性能提升。例如:
product.name = 'Name changed again'
product.save(update_fields=['name'])
update_fields
参数可以是任何包含字符串的可迭代对象。空的update_fields
可迭代对象将会忽略保存。如果为None
值,将执行所有字段上的更新。
指定
update_fields
将强制使用更新操作。
当保存通过延迟模型加载(
only()
或defer()
)进行访问的模型时,只有从数据库中加载的字段才会得到更新。这种情况下,有个自动的update_fields
。如果你赋值或者改变延迟字段的值,该字段将会添加到更新的字段中。
new in 1.9
使用Model.delete()
删除多表继承的子表数据时,使用``keep_parents=True可以保留上级数据,默认为
False`
返回值为删除数据的条数
DateField
和DateTimeField
字段如果null=False
则支持下面两个方法
Model.get_next_by_FOO(**kwargs)¶
Model.get_previous_by_FOO(**kwargs)
django遇到的第一个管理器为默认管理器
如果需要访问关联对象调用关联对象的默认管理器,需要在管理器中加use_for_related_fields=True
,不然会调用朴素管理器
# -*- coding: utf-8 -*-
from django.db import models
class DefaultManager(models.Manager):
def get_queryset(self):
queryset = super(DefaultManager, self).get_quertset().filter(is_delete=False)
return queryset
class Author(models.Model):
name = models.CharField(max_length=100)
is_delete = models.BooleanField()
objects = DefaultManager()
class Post(models.Model):
author = models.ForeignKey(Author)
title = models.CharField(max_length=100)
content = models.TextField()
is_delete = models.BooleanField()
objects = DefaultManager()
author = Author.objects.get(pk=1)
post = Post.objects.get(pk=2)
# 调用DefaultManager管理器
author.post_set.all()
# 调用朴素管理器,如果要调用DefaultManager管理器,需要设置DefaultManager管理器的类变量use_for_related_fields=True
post.author
注:朴素管理器里找不到的方法会在默认管理器里查找
Manager.raw(raw_query, params=None, translations=None)
django.db.connection对象提供了常规数据库连接的方式。为了使用数据库连接,先要调用connection.cursor()方法来获取一个游标对象之后,调用cursor.execute(sql, [params])来执行sql语句,调用cursor.fetchone()或者cursor.fetchall()来返回结果行。
详细笔记见django1.8事务.md
将每个HTTP请求封装在一个数据库事务中
settings中设置ATOMIC_REQUESTS=True
单独给一个方法加上数据库事务控制使用atomic
from django.db import transaction
@transaction.atomic
def viewfunc(request):
# This code executes inside a transaction.
do_stuff()
或
from django.db import transaction
def viewfunc(request):
# This code executes in autocommit mode (Django's default).
do_stuff()
with transaction.atomic():
# This code executes inside a transaction.
do_more_stuff()
避免在 atomic里捕获异常!
使用数据库的方法
from django.db.models import Func, F
queryset.annotate(field_lower=Func(F('field'), function='LOWER'))
或
class Lower(Func):
function = 'LOWER'
queryset.annotate(field_lower=Lower(F('field')))
高级用法查看在线版
When
Case
Coalesce
接收一个含有至少两个字段名称或表达式的列表,返回第一个非空的值(空字符串不认为是一个空值)
根据遗留数据库生成models
python manage.py inspectdb > models.py
使用fixtures
[
{
"model": "myapp.person",
"pk": 1,
"fields": {
"first_name": "John",
"last_name": "Lennon"
}
},
{
"model": "myapp.person",
"pk": 2,
"fields": {
"first_name": "Paul",
"last_name": "McCartney"
}
}
]
导入数据命令
python manage.py loaddata <fixturename>
添加索引,比任何查询语法优化都来的重要
理解查询集
QuerySets是延迟的。
什么时候它们被计算出来。
数据在内存中如何存储。
使用cached_property
装饰器,只要是同一个实例,一个方法就只会执行一次
使用with
模版标签
使用iterator
迭代器
在数据库中而不是python中做数据库工作
使用过滤器和反射过滤器对数据进行过滤
使用F()
表达式
使用注解和聚合
使用原始SQL
用唯一的或被索引的列来检索独立对象
在不同位置多次访问数据库,每次获取一个数据集,不如在一次查询中获取它们。比如循环的时候。
使用select_related()
和prefetch_related()
不检索你不需要的信息
使用QuerySet.values()
和QuerySet.values_list()
使用QuerySet.defer()
和QuerySet.only()
计算数量不要使用len(queryset)
而是使用QuerySet.count()
判断是否存在结果使用QuerySet.exists()
而不是用if queryset
但不要过度使用count()
和exists()
,如果你本来就需要里面的数据,那就不要使用
使用QuerySet.update()
和QuerySet.delete()
批量操作数据
直接使用外键的值
entry.blog_id
# 而不是
entry.blog.id
如果你并在意结果集的顺序,不要进行排序,移除Meta.ordering
创建对象时尽可能使用bulk_create()
来减少sql查询数量
这也适用于ManyToManyFields
的情况,一起add
而不是一个一个add
my_band.members.add(me, my_friend)
#更优于
my_band.members.add(me)
my_band.members.add(my_friend)
url捕获的参数永远是字符串
在根url上获取的参数不影响参数传递
# In settings/urls/main.py
from django.conf.urls import include, url
urlpatterns = [
url(r'^(?P<username>\w+)/blog/', include('foo.urls.blog')),
]
# In foo/urls/blog.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.blog.index),
url(r'^archive/$', views.blog.archive),
]
在上面的例子中,捕获的"username"变量将被如期传递给include()指向的URLconf。
可嵌套
from django.conf.urls import url
urlpatterns = [
url(r'blog/(page-(\d+)/)?$', blog_articles), # bad
url(r'comments/(?:page-(?P<page_number>\d+)/)?$', comments), # good
]
传递额外的参数
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
]
当url捕获的参数和字典中传递的参数同名时,将忽略url捕获的参数而使用字典里的参数值
传递额外的参数给include()
# main.py
from django.conf.urls import include, url
urlpatterns = [
url(r'^blog/', include('inner'), {'blogid': 3}),
]
# inner.py
from django.conf.urls import url
from mysite import views
urlpatterns = [
url(r'^archive/$', views.archive),
url(r'^about/$', views.about),
]
效果等同
# main.py
from django.conf.urls import include, url
from mysite import views
urlpatterns = [
url(r'^blog/', include('inner')),
]
# inner.py
from django.conf.urls import url
urlpatterns = [
url(r'^archive/$', views.archive, {'blogid': 3}),
url(r'^about/$', views.about, {'blogid': 3}),
]
HttpResponse
子类,状态码
HttpResponseRedirect
临时重定向,302HttpResponsePermanentRedirect
永久重定向,301HttpResponseNotModified
没有任何修改,304HttpResponseBadRequest
语义有误码,当前请求不被服务器理解,400HttpResponseNotFound
页面没找到,404HttpResponseForbidden
服务器理解请求,但拒绝执行,403HttpResponseNotAllowed
请求中指定的请求方式不能用于请求相应资源,405HttpResponseGone
请求的资源在服务器上已经不可用,而且没有已知的转发地址,410HttpResponseServerError
服务器遇到了一个意外的错误,导致无法完成对请求的处理,500HttpResponse(status=201)
自定义返回状态码重写错误视图(在url中)
handler404 = 'mysite.views.my_custom_page_not_found_view'
handler500 = 'mysite.views.my_custom_error_view'
handler403 = 'mysite.views.my_custom_permission_denied_view'
handler400 = 'mysite.views.my_custom_bad_request_view'
template_name
可传一个模版序列,django将使用存在的第一个模版
redirect(to, [permanent=False, ]*args, **kwargs)[source]
为传递进来的参数返回HttpResponseRedirect 给正确的URL 。
参数可以是:一个模型:将调用模型的get_absolute_url() 函数 一个视图,可以带有参数:将使用urlresolvers.reverse 来反向解析名称 一个绝对的或相对的URL,将原样作为重定向的位置。
默认返回一个临时的重定向;传递permanent=True 可以返回一个永久的重定向。
get_object_or_404(klass, *args, **kwargs)
可以传Model也可以传QuerySet实例和关联的管理器
get_list_or_404(klass, *args, **kwargs)
可以传Model也可以传QuerySet实例和关联的管理器
按需内容处理
django.views.decorators.http
包里的装饰器可以基于请求的方法来限制对视图的访问。若条件不满足会返回 django.http.HttpResponseNotAllowed。
require_http_methods(request_method_list)
限制视图只能服务于规定的http方法(需要大写)
require_GET()
require_POST()
require_safe()
只允许视图接受GET和HEAD方法的装饰器。
@condition(etag_func=None, last_modified_func=None)
@last_modified(last_modified_func)
根据最后修改时间来决定是否运行视图,可减少流量
@etag(etag_func)
etag
(版本?)和last_modified
不能同时使用
GZip
对内容进行压缩,节省流量,但增加处理时间
vary_on_cookie
vary_on_headers
基于特定的请求头部来控制缓存
never_cache
HttpRequest
对象(除非特殊说明,所有属性都是只读,session
属性是个例外)
HttpRequest.scheme
请求方案(通常为http或https)
HttpRequest.body
字节字符串,表示原始http请求正文
HttpRequest.path
字符串,表示请求的页面的完整路径,不包含域名
HttpRequest.path_info
在某些Web 服务器配置下,主机名后的URL 部分被分成脚本前缀部分和路径信息部分。path_info 属性将始终包含路径信息部分,不论使用的Web 服务器是什么。使用它代替path 可以让代码在测试和开发环境中更容易地切换。
例如,如果应用的WSGIScriptAlias 设置为"/minfo",那么当path 是"/minfo/music/bands/the_beatles/" 时path_info 将是"/music/bands/the_beatles/"。
HttpRequest.method
请求使用的http方法,大写
HttpRequest.encoding
表示提交的数据的编码方式,可写
HttpRequest.GET
HttpRequest.POST
HttpRequest.REQUEST
不建议使用,使用GET
和POST
代替
HttpRequest.COOKIES
字典,键和值都是字符串
HttpRequest.FILES
类似字典的对象,包含所有的上传文件,
Form.auto_id
Field.has_change()
BooleanField
CharField
ChoiceField
TypeChoiceField
DateField
DateTimeField
DecimalField
DurationField
EmailField
FileField
FilePathField
FloatField
ImageField
IntegerField
IPAddressField
GenericIPAddressField
MultipleChoiceField
TypedMultipleChoiceField
NullBooleanField
RegexField
SlugField
TimeField
URLField
UUIDField
ComboField
MultiValueField
SplitDateTimeField
ModelChoiceField
ModelMultipleChoiceField