<script>
alert("hello")
</script>
def _get_server(self, key):
if isinstance(key, tuple):
serverhash, key = key
else:
serverhash = serverHashFunction(key)
if not self.buckets:
return None, None
for i in range(Client._SERVER_RETRIES):
server = self.buckets[serverhash % len(self.buckets)]
if server.connect():
# print("(using server %s)" % server,)
return server, key
#连接不上就换人,打算损失一部分缓存数据
serverhash = str(serverhash) + str(i)
if isinstance(serverhash, six.text_type):
serverhash = serverhash.encode('ascii')
serverhash = serverHashFunction(serverhash)
return None, None
def cmemcache_hash(key):
return (((binascii.crc32(key) & 0xffffffff) >> 16) & 0x7fff) or 1
serverHashFunction = cmemcache_hash
https://github.com/linsomniac/python-memcached/blob/master/memcache.py
https://github.com/lericson/pylibmc
参数配置
CACHE_MIDDLEWARE_ALIAS 缓存别名(默认:default)
CACHE_MIDDLEWARE_SECONDS – 每个页面的缓存时间(s)(默认:600s)
CACHE_MIDDLEWARE_KEY_PREFIX – 如果缓存被多个使用相同 Django 安装的站点共享,配置此参数为站点名称或其它能代表站点的唯一字符串,以防止key冲突。如果不在意,可为空。
//对中间件进行说明
FetchFromCacheMiddleware
会缓存 GET 和 HEAD 200 状态的 responses,而且这些 request 和 response 的headers 是允许的;
同一个 URL request, 不同查询参数,他的 Responses 会被作为不同 page 分别缓存;
这个中间件期待用具有相同 response headers 的 GET request 的response 进行响应,这样它就可以用缓存的 GET response 响应 HEAD request。
UpdateCacheMiddleware
此中间件会在每个 HttpResponse 中自动设置一些 headers:
对于一个页面的新版本(未被缓存过)的请求,设置 Last-Modified header 为当前日期/时间;
设置 Expires header 为当前时期/时间 + 定义的CACHE_MIDDLEWARE_SECONDS
设置 Cache-Control header 的 max age 指令为 CACHE_MIDDLEWARE_SECONDS (max age是指缓存的内容将在多少秒后失效)
特殊情况:
如果 view 设置了自己的 cache 过期时间 (如:设置了 Cache-Control 的 max-age), 则页面的缓存过期时间会以 view 的过期时间为准。
http://www.maiziedu.com/wiki/django/lowlevel/
http://www.maiziedu.com/wiki/django/backend/
http://www.hi-roy.com/2015/08/13/python-memcached%E6%BA%90%E7%A0%81%E5%B0%8F%E7%AA%A5/
http://xdxd.love/2016/01/14/CRC32%E7%AE%97%E6%B3%95%E8%AF%A6%E8%A7%A3%E5%92%8C%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF/
logging.getLogger(__name__).
That’s because in a module, __name__ is the module’s name in the Python package namespace.
package.filename
# 何时求值
QuerySet 本身是可迭代的,返回的iter
迭代 切片 序列化 repr() len() list() bool()
# pickle存QuerySet对象,会先求值
dump
blogs = Blog.objects.all()
pickle.dump(blogs, fd, True)
load
blogs = pickle.load(fd)
print blogs[0].name # not hit db
import cPickle as pickle
pickle.dump(obj, file[, protocol])
pickle.load(file)
dumps(obj, protocol=None)
loads(str)
更快更节省存储空间。
protocol=True则以高压缩的二进制格式保存持久化后的对象,否则以ASCII格式保存。
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline='Hello')
用SQL 语句,它等同于:
SELECT ...
WHERE NOT pub_date > '2005-1-3'
AND NOT headline = 'Hello'
感觉不如Q语句那样直白。
from django.db.models import Q
b = Author.objects.exclude(Q(name__contains='a') | Q(email__contains='5'))
# annotate
例如,如果你正在操作一个Blog 列表,你可能想知道每个Blog 有多少Entry:
>>> from django.db.models import Count
>>> q = Blog.objects.annotate(Count('entry'))
# The name of the first blog
>>> q[0].name
'Blogasaurus'
# The number of entries on the first blog
>>> q[0].entry__count
42
Blog 模型本身没有定义entry__count 属性,但是通过使用一个关键字参数来指定聚合函数,你可以控制Annotation 的名称:
>>> q = Blog.objects.annotate(number_of_entries=Count('entry'))
# The number of entries on the first blog, using the name provided
>>> q[0].number_of_entries
42
# values values_list 取出特定列,不转为QuerySet
values(*field)
values_list(*field)
values_list(*field, flat=True) 仅限单字段
外键将会返回 字段_id 作为字典key
多对多 等待测试
# only defer
only(*field) #仅返回特定列(会自动包括id),转为QuerySet
defer(*field) #排除
# order_by
order_by('name')
order_by('-name')
#dates(field, kind, order='ASC')
返回DateQuerySet - QuerySet,其计算结果为datetime.date对象列表,表示特定种类的所有可用日期QuerySet。
field应为模型的DateField的名称。 kind应为"year"、"month"或"day"。隐式的是升序排序。若要随机排序,请使用"?",像这样:
"year" 返回对应该field的所有不同年份值的list。
“month”返回字段的所有不同年/月值的列表。
“day”返回字段的所有不同年/月/日值的列表。
等待测试 用于blog的日期分类
Entry.objects.dates('pub_date', 'year') # 返回entry中出版日期不同年的文章。
文章选择列表可以搞出来不同月份发表的分类,然后根据月份去查找相应的文章。
#select_related
filter() 和select_related() 链的顺序不重要。下面的查询集是等同的:
Entry.objects.filter(pub_date__gt=timezone.now()).select_related('blog')
Entry.objects.select_related('blog').filter(pub_date__gt=timezone.now())
select_related('blog') 必须是外键字段或onetoone
from django.db import models
class City(models.Model):
# ...
pass
class Person(models.Model):
# ...
hometown = models.ForeignKey(City)
class Book(models.Model):
# ...
author = models.ForeignKey(Person)
外键可以一直传下去
Book.objects.select_related('author__hometown')
默认的Book.objects.select_related()不加参数会自动关联所有的外键字段。
过滤外键字段的时候需要__
e = Entry.objects.select_related().only('blog__name', 'headline').get(pk=1)
e.pub_date # hit db
e.blog.tagline # hit db
select_related('foo', 'bar')
等同于select_related('foo').select_related('bar')
#prefetch进行两步sql操作。
1:主表中数据拉出来
2:关系表与中间表join,where id in 主表id
prefetch后会关联填充在QuerySets中,后续对关联字段的读取不会hit db,而是在QuerySets中获取。
但是只能是all(),后续的改变如pizza.toppings.filter()将创建新的query,hit db而不会用QuerySets。
过滤主表
es = Entry.objects.prefetch_related('authors').filter(headline__contains='l')
{u'time': u'0.001', u'sql': u"SELECT `blog_entry`.`id`, `blog_entry`.`blog_id`, `blog_entry`.`headline`, `blog_entry`.`body_text`, `blog_entry`.`pub_date`, `blog_entry`.`mod_date`, `blog_entry`.`n_comments`, `blog_entry`.`n_pingbacks`, `blog_entry`.`rating` FROM `blog_entry` WHERE `blog_entry`.`headline` LIKE BINARY '%l%'"}
{u'time': u'0.001', u'sql': u'SELECT (`blog_entry_authors`.`entry_id`) AS `_prefetch_related_val_entry_id`, `blog_author`.`id`, `blog_author`.`name`, `blog_author`.`email` FROM `blog_author` INNER JOIN `blog_entry_authors` ON (`blog_author`.`id` = `blog_entry_authors`.`author_id`) WHERE `blog_entry_authors`.`entry_id` IN (1, 2)'}
过滤关联表
尝试在pre_related的时候filter,发现sql语句变了。
es = Entry.objects.prefetch_related('authors').filter(authors__name__contains='N')
相应的sql如下:
{u'time': u'0.000', u'sql': u"SELECT `blog_entry`.`id`, `blog_entry`.`blog_id`, `blog_entry`.`headline`, `blog_entry`.`body_text`, `blog_entry`.`pub_date`, `blog_entry`.`mod_date`, `blog_entry`.`n_comments`, `blog_entry`.`n_pingbacks`, `blog_entry`.`rating` FROM `blog_entry` INNER JOIN `blog_entry_authors` ON (`blog_entry`.`id` = `blog_entry_authors`.`entry_id`) INNER JOIN `blog_author` ON (`blog_entry_authors`.`author_id` = `blog_author`.`id`) WHERE `blog_author`.`name` LIKE BINARY '%N%'"}
不知道为啥直接粗暴的join了???
如同select_related一样,也是可以链式关联下去的 __ 连接字段即可。
#批量插入
bulk_create(objs, batch_size=None)
此方法以有效的方式(通常只有1个查询,无论有多少对象)将提供的对象列表插入到数据库中:
>>> Entry.objects.bulk_create([
... Entry(headline="Django 1.0 Released"),
... Entry(headline="Django 1.1 Announced"),
... Entry(headline="Breaking: Django is awesome")
... ])
这有一些注意事项:
将不会调用模型的save()方法,并且不会发送pre_save和post_save信号。
# count
Entry.objects.count()
count()在后台执行SELECT COUNT(*) count(),很快的!
#iterator
a = Author.objects.all()
for i in a:
print i # hit db
for i in a:
print i # not hit db
for i in a.iterator():
print i # hit db
connection.queries
iterator不会缓存结果,而是直接数据库一点点取。对于返回大量数据性能较好。
#日期字段的快捷方式latest earliest
Entry.objects.latest('pub_date')
没有啥技巧,select按照日期字段order_by而已。
#update
update()方法立即应用,对更新的QuerySet的唯一限制是它只能更新模型主表中的列,而不是相关模型。
Author.objects.update(email='666@qq.com')
for i in Author.objects.all():
print i.name, i.email
一旦分片或者求值后就不能update的了
只能python方式修改
e = Entry.objects.get(id=10)
e.comments_on = False
e.save()
#delete
默认情况下,Django的ForeignKey模拟SQL约束ON DELETE CASCADE字,任何具有指向要删除的对象的外键的对象将与它们一起被删除。
模拟,其实是一步步删除,先删除关联,在删除被关联表。
同样,不能对分片或求值的进行delete操作。
# in
Entry.objects.filter(id__in=[1, 3, 4])
SQL等效:
SELECT ... WHERE id IN (1, 3, 4);
# range
范围测试(包含于之中)。
import datetime
start_date = datetime.date(2005, 1, 1)
end_date = datetime.date(2005, 3, 31)
Entry.objects.filter(pub_date__range=(start_date, end_date))
search
一个Boolean类型的全文搜索,以全文搜索的优势。这个很像 contains ,但是由于全文索引的优势,以使它更显著的快。
Entry.objects.filter(headline__search="+Django -jazz Python")
#其他lookup
gt gte le lte startswith istartswith endswith iendswith
year month day week_day hour minute second