标签:style blog http color 使用 io 数据 for
上一篇写到MakingQuey中的filter,本篇接着来。
10)-扩展多值的关系
如果对一个ManyToManyField或ForeignKey的表进行filter过滤查询的话,有2中方法可以用。分别是:
#1 Blog.objects.filter(entry__headline__contains=‘Lennon‘, entry__pub_date__year=2008) #2 Blog.objects.filter(entry__headline__contains=‘Lennon‘).filter( entry__pub_date__year=2008)
假设,现有一个blog表,它对应了很多的entry的表,而且这个blog既有含有“Lennon”的entry,也有含有2008的entry,但是没有那种2者都有的entry,那么第一个方法过滤的是2者都有的entry,所以没有符合条件的blog返回。第一种方法可以理解为“并且”的意思。第二种是第一个filter返回含有“Lennon”的blog,然后在这个blog集合中,再选有2008的,所以会有blog返回。开始理解起来很费劲,抓住特点:一个blog对应多个entry。例如,blog1对应了entry1,entry2,entry3,其中entry1只有“Lennon”,没有2008;entry2只有2008,没有“Lennon”;entry3则什么都没有。那么用第一种方法来filter的时候,则没有满足既有Lennon又有2008的entry;第二种方法的第一个filter,因为entry1有Lennon,所以blog1为返回值,然后对返回值blog1进行filter,条件为有2008,而blog1中的entry2是有2008的,所以blog1作为返回值。
这个也适用于exlude().
11)-filters可以引用model中的fields
class F
目前为止的例子中,都是用field中的值来作为filter的条件来进行数据查询。但是如果需要把一个field的值与他所在的model的其他field的值呢?
django提供F()表达式来实现这种比较。F()的实例是在一个query中来对model中的field进行引用。这些引用可以作为filter的条件来进行过滤。
例如,要查询blog的entry,comments满足的数量比pingbacks的多,可以用F()来作用在pingbacks上,然后把结果作为filter的条件:
>>> from django.db.models import F >>> Entry.objects.filter(n_comments__gt=F(‘n_pingbacks‘))
注意:F()表达式中是n_comments比大n_pingbacks。所以,也有倍数、加、减这样的操作可以来比较:
>>> Entry.objects.filter(n_comments__gt=F(‘n_pingbacks‘) * 2)#
n_comments比n_pingbacks的2倍多
>>> Entry.objects.filter(rating__lt=F(‘n_comments‘) + F(‘n_pingbacks‘))#n_comments与n_pingbacks的和比rating多
gt是多理解为>,lt理解为<.
而下面的例子则是两个字符串一样:
>>> Entry.objects.filter(authors__name=F(‘blog__name‘))
12)-pk
是primary key的意思:
>>> 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
# Get blogs entries with id 1, 4 and 7 >>> Blog.objects.filter(pk__in=[1,4,7]) # Get all blog entries with id > 14 >>> Blog.objects.filter(pk__gt=14)
同样应该有这些符号的组合,分别是__双下划线,lt,gt,exact等等。
如果查询含有%符号的,下例给出:
>>> Entry.objects.filter(headline__contains=‘%‘)
同样的_下划线符号也是,django会自动来处理的,就像上边这行程序这样写就行了。
5-QuerySet的缓存
每个QuerySet都有缓存来降低对数据库database的访问。弄明白了之后,可以写出高效率的代码。
在新创建的QuerySet中,缓存是空的。当QuerySet第一次 被计算的时候,django把QuerySet放在其缓存中,然后把具体要查询的数据项作为结果返回。把QuerySet这种缓存的行为时刻记住,有的时候很容易使用不当的。例如下面,建立了2个QuerySet,分别使用后,就丢掉了,这样造成了2次访问database,而且第二个e很可能不是第一个e,因为在第二个发生之前,database很可能已经被写入新数据或删除什么东西了:
>>> 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.
注意,第一行并没有touch the database,访问数据库发生在第二行代码。
QuerySet也并不是总缓存结果的,当计算queryset的一部分的时候,要缓存,但是如果只是用一个下一层的queryset来访问结果的时候,并没有缓存。这也意味着,可以用数组分片或者一个索引来限制queryset而不产生缓存,例如下面的例子,显示只定义了一个queryset来存放objects,然后用数组来访问其中的某一个,这样就没有缓存,每次都要重新访问数据库:
>>> 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
还有一些例子也是整个querset都被计算了,当然产生了缓存:
>>> [entry for entry in queryset] >>> bool(queryset) >>> entry in queryset >>> list(queryset)
6-用Q对象来进行复杂的查询
在filter()方法中,用关键字来查询,这些关键字是AND的关系,即”并且“,如果需要进行更复杂的查询,例如OR关系,可以用Q对象这种方法。
Q对象(django.db.models.Q)是用来封装关键字的集合的。这些关键字包括上文的lookup查询中所提到的关键字。例如,下面这个Q对象封装了LIKE查询:
from django.db.models import Q Q(question__startswith=‘What‘)
Q对象可以用逻辑符号&或者|来连接,结果返回一个Q对象:
Q(question__startswith=‘Who‘) | Q(question__startswith=‘What‘)
同等于SQL语句:
WHERE question LIKE ‘Who%‘ OR question LIKE ‘What%‘
可以把Q对象组合成复杂的表达,也可以用~符号,代表”NOT,非“的意思:
Q(question__startswith=‘Who‘) | ~Q(pub_date__year=2005)
每个查询函数(filter(), get(), exclude())都需要有关键字,Q对象就可以作为这些查询函数的关键字:
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‘)
查询函数也可以混合使用keywords和Q object,但是要注意,Q object必须在keyword之前定义:
#正确的 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)))
7-比较对象
用python标准的比较操作符==就可以进行model实例的比较。而这实际上实在比较primarykey的值:
>>> some_entry == other_entry >>> some_entry.id == other_entry.id#实际上
如果model的primarykey不叫id,没关系,照样还是在比较primarykey,例如一个model的primarykey是name,则下面2行代码是同样意思的:
>>> some_obj == other_obj
>>> some_obj.name == other_obj.name
8-删除对象
delete()用来进行对象的删除,而且是立即生效,并且没有返回值:
e.delete()
也可以批量来进行删除操作,每个QuerySet都有delete()操作,可以把QuerySet中的所有对象都删掉:
Entry.objects.filter(pub_date__year=2005).delete()
delete是Manager的一个方法,但是由于怕用户误操作而没有显式的显现出来。因为delete是纯粹的在SQL中执行的方法,所以不需要用户在过程中去认为的调用。如果你在一个model的class定义中自己定义了一个delete()的话,那么就相当于覆盖掉了Manager提供的delete,这样就需要用户自己去调用了,而且这种自己定义的delete()还不能批量的来操作,也就是不能作为QuerySet中的参数来调用,而是需要自己对每个object单独进行delete一次。
django提供的delete()方法,会删除由foreignkey来关联到一起的object:
b = Blog.objects.get(pk=1) # This will delete the Blog and all of its Entry objects. b.delete()
这种串联的用法是通过 on_delete 参数传递给Foreignkey的。
delete是Manager的一个方法,为了防止用户误操作,所以不用显式调用,但是如果确实需要调用delete()来删除所有的objects的话,应该明确的指出来这个QuerySet:
Entry.objects.all().delete()
9-复制model实例
尽管没有built-in的方法来实现model 实例的复制,但是可以用model的所有的fields的值来创建一个新的实例,最简单的情况就是,先把pk设置成None,然后再save:
1 blog = Blog(name=‘My blog‘, tagline=‘Blogging is easy‘) 2 blog.save() # blog.pk == 1 3 4 blog.pk = None 5 blog.save() # blog.pk == 2
思考:也就是,第1行代码只是把Blog内容放在了blog这个变量中,并没写进去数据库,只有调用save()方法时,才发生写的操作。而且每当调用save(),都相当于要把这个数据(blog)写进数据库。而数据库的pk是唯一而不能重复的,所有先要把blog.pk设成None,然后再操作,由SQL语句把pk由依次递增为2了。
如果有model的继承时,会略复杂一些:
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
因为继承的工作原理,这次需要把pk和id都设成None了:
django_blog.pk = None django_blog.id = None django_blog.save() # django_blog.pk == 4
这个过程并没有复制相关联的objects,如果想要复制这种关系,需要多写一些代码了。在本文的例子中,Entry和Author是多对多的关系(ManyToManyField):
1 entry = Entry.objects.all()[0] # some previous entry 2 old_authors = entry.authors.all() 3 entry.pk = None 4 entry.save() 5 entry.authors = old_authors # saves new many2many relations
今天到这,明天继续!
django学习之Model(四)MakingQuery,布布扣,bubuko.com
标签:style blog http color 使用 io 数据 for
原文地址:http://www.cnblogs.com/ee2213/p/3919669.html