django数据库查询.docx
《django数据库查询.docx》由会员分享,可在线阅读,更多相关《django数据库查询.docx(10页珍藏版)》请在冰豆网上搜索。
django数据库查询
django数据库查询
classPoll(models.Model):
slug=models.SlugField(unique_for_month='pub_date')
question=models.CharField(maxlength=255)
pub_date=models.DateTimeField()
expire_date=models.DateTimeField()def__repr__(self):
returnself.questionclassMeta:
get_latest_by='pub_date'classChoice(models.Model):
poll=models.ForeignKey(Poll,edit_inline=models.TABULAR,
num_in_admin=10,min_num_in_admin=5)
choice=models.CharField(maxlength=255,core=True)
votes=models.IntegerField(editable=False,default=0)def__repr__(self):
returnself.choice及下面的简单会话:
>>>fromdatetimeimportdatetime
>>>p1=Poll(slug='whatsup',question="What'sup?
",
...pub_date=datetime(2005,2,20),expire_date=datetime(2005,4,20))
>>>p1.save()
>>>p2=Poll(slug='name',question="What'syourname?
",
...pub_date=datetime(2005,3,20),expire_date=datetime(2005,3,25))
>>>p2.save()
>>>Poll.objects.all()
[What'sup?
What'syourname?
]查询如何运作Django的数据查询基于构建结果集及对结果集进行取值.结果集是独立于数据库的符合某个查询条件的一组数据对象的集合.这是一个惰性集合:
在对该集合取值之前,无法知道该集合有哪些成员.要生成一个满足你需求的结果集,首先要得到一个描述给定类型的所有对象的初始结果集.这个初始结果集可以通过一系列函数进行更精细的优化处理.当经过处理后的结果集符合你的要求时,就可以对它进行取值操作(使用迭代操作,slicing操作,或一系列其它技术),以得到一个你需要的对象或对象的列表.
获得初始结果集每个Djangomodel都有一个与生俱来的管理器对象objects,管理器最重要的角色就是作为初始结果的来源.一个管理器就是一个描述给定类型所有对象的特殊的初始结果集.Poll.objects就是包含所有Poll对象的一个初始结果集.它唯一特殊之处在于它不能被取值.要克服此限制,管理器对象有一个all()方法.该方法生成一个可以被取值的初始结果集的拷贝:
all_polls=Poll.objects.all()参阅ModelAPI的Managers小节以了解管理器的定位及创建细节.
优化定制结果集管理器提供的初始结果集描述了给定类型的所有对象.不过通常你只需要这个对象集合中的一小部分(一个子集).要生这样一个结果集,你需要对初始结果集进行优化定制处理,增加一些限制条件直到描述的子集满足你的需要.最常用的两个定制结果集的方法是:
filter(**kwargs)
返回一个匹配查询参数的新的结果集.
exclude(**kwargs)
返回一个不匹配查询参数的新的结果集.参数格式在下面"字段查询"小节有描述.这两个方法的返回值都是结果集对象,因此结果集可以进行链式处理:
Poll.objects.filter(
question__startswith="What").exclude(
pub_date__gte=datetime.now()).filter(
pub_date__gte=datetime(2005,1,1))...以一个初始结果集作为参数,然后进行过滤,再进行排除,再进行另一个过滤.这样得到的最终结果就一个问题开头单词是"What",发布日期在2005年1月1日至今的所有民意测验的集合.每个结果集都是一个独一无二的对象.以上操作的每一步都生成了一个新的结果集:
q1=Poll.objects.filter(question__startswith="What")
q2=q1.exclude(pub_date__gte=datetime.now())
q3=q1.filter(pub_date__gte=datetime.now())这三步生成了三个结果集;一个初始结果集包含所有的以"What"开头的民意测验,两个初始结果集的子集(一个排除条件,一个过滤条件).对原始结果集的改进过程并没有影响到原始的结果集.值得注意的是结果集的创建根本没有访问数据库.只有当对结果集取值时才会访问数据库.
字段查询以field__lookuptype(注意是双下线)形式进行基本的字段查询,举例来说:
polls.objects.filter(pub_date__lte=datetime.now())该查询翻译成SQL就是:
SELECT*FROMpolls_pollsWHEREpub_date<=NOW();实现细节Python能够在定义函数时接受任意的name-value(names和values均可以在运行时通过计算得到)参数.要了解更多信息,参阅官方Python教程中的关键字参数.DBAPI支持下列查找类型:
类型描述
exact精确匹配:
polls.get_object(id__exact=14).
iexact忽略大小写的精确匹配:
polls.objects.filter(slug__iexact="foo")匹配foo,FOO,fOo,等等.
contains大小写敏感的内容包含测试:
polls.objects.filter(question__contains="spam")返回question中包含"spam"的所有民意测验.(仅PostgreSQL和MySQL支持.SQLite的LIKE语句不支持大小写敏感特性.对Sqlite来说,contains等于icontains.)
icontains大小写不敏感的内容包含测试:
gt大于:
polls.objects.filter(id__gt=4).
gte大于等于.
lt小于.
lte小于等于.
ne不等于.
in位于给定列表中:
polls.objects.filter(id__in=[1,3,4])返回一个polls列表(ID值分别是1或3或4).
startswith大小写敏感的starts-with:
polls.objects.filter(question__startswith="Would").(仅PostgreSQL和MySQL支持.SQLite的LIKE语句不支持大小写敏感特性.对Sqlite来说,``startswith``等于istartswith)
endswith大小写敏感的ends-with.(仅PostgreSQL和MySQL)
istartswith大小写不敏感的starts-with.
iendswith大小写不敏感的ends-with.
range范围测试:
polls.objects.filter(pub_date__range=(start_date,end_date))返回pub_date位于start_date和end_date(包括)之间的所有民意测验
year对date/datetime字段,进行精确的年匹配:
polls.get_count(pub_date__year=2005).
month对date/datetime字段,进行精确的月匹配:
day对date/datetime字段,进行精确的日匹配:
isnullTrue/False;做IFNULL/IFNOTNULL查询:
polls.objects.filter(expire_date__isnull=True).如果未提供查找类型,系统就认为查找类型是exact.下面两个语句是等价的:
Poll.objects.get(id=14)
Poll.objects.get(id__exact=14)查询允许多个条件参数,逗号分隔的多个条件参数会被"AND"起来使用:
polls.objects.filter(
pub_date__year=2005,
pub_date__month=1,
question__startswith="Would",
)...得到2005年1月公布的带有一个"Would"开头的问题的所有民意测验.为了使用更加方便,还提供有一个pk查找类型,可以翻译成(primary_key)__exact.在这个民意测试的例子里,下面两个语句是等价的.:
polls.get_object(id__exact=3)
polls.get_object(pk=3)pk也可以通过连接进行查询.在这个民意测试的例子里,下面两个语句是等价的:
choices.objects.filter(poll__id__exact=3)
choices.objects.filter(poll__pk=3)如果传递的关键字参数非法,将引发TypeError异常.
OR查询关键字参数查询的各个条件都是"AND"关系.如果你需要一个复杂的查询(举例来说,你需要一个OR语句),你需要使用Q对象.Q对象是django.core.meta.Q的实例,用来装载一系列关键字参数.这些关键字参数就象指定给get()和filter()函数的关键字参数一样.举例来说:
Q(question__startswith='What')Q对象可以使用&和|运算符进行组合.当两个Q对象进行&或|运算时,会生成一个新的Q对象.举例来说语句:
Q(question__startswith='Who')|Q(question__startswith='What')...生成一个新的Q对象表示这两个"question__startswith"查询条件的"OR"关系.等同于下面的SQLWHERE子句:
...WHEREquestionLIKE'Who%'ORquestionLIKE'What%'通过对多个Q对象的&和|运算你能得到任意复杂的查询语句.也可以使用圆括号分组.查询函数可以接受一个或多个Q对象作为参数.如果提供有多个Q对象参数,它们将被"AND"到一起.举例来说:
polls.get_object(
Q(question__startswith='Who'),
Q(pub_date__exact=date(2005,5,2))|Q(pub_date__exact=date(2005,5,6))
)...翻译成SQL就是这样:
SELECT*frompollsWHEREquestionLIKE'Who%'
AND(pub_date='2005-05-02'ORpub_date='2005-05-06')如果需要,查询函数可以混合使用Q对象参数和关键字参数.所有提供给查询函数的参数(不管是关键字参数还是Q对象)都被"AND"到一起.如果提供了Q对象作为参数,它就必须在其它关键字参数(如果有的话)的前面.举例来说:
polls.get_object(
Q(pub_date__exact=date(2005,5,2))|Q(pub_date__exact=date(2005,5,6)),
question__startswith='Who')...这是一个合法的查询,等价于前一个例子,不过:
#INVALIDQUERY
polls.get_object(
question__startswith='Who',
Q(pub_date__exact=date(2005,5,2))|Q(pub_date__exact=date(2005,5,6)))...这个查询则不符合我们的规则,会引发异常.Q对象也可以以complex关键字参数的形式使用.举例来说:
polls.get_object(
complex=Q(question__startswith='Who')&
(Q(pub_date__exact=date(2005,5,2))|
Q(pub_date__exact=date(2005,5,6))
)
)参阅OR查询示例以阅读更多实例.
从结果集中取值只有通过取值操作才能得到结果集包含的对象.取值操作可以通过迭代,切片,或其它专门的函数来实现.一个结果集就是一个可迭代对象.因此,可以通过一个循环来取出它的值:
forpinPoll.objects.all():
printp将使用Poll对象的__repr__()方法打印出所有的Poll对象.一个结果集也可以被切片,使用数组符号操作:
fifth_poll=Poll.objects.all()[4]
all_polls_but_the_first_two=Poll.objects.all()[2:
]
every_second_poll=Poll.objects.all()[:
:
2]结果集对象是惰性对象-也就是说,他们不是真正的包含他们表示对象的集合(或列表).Python的协议魔法让结果集看起来是一个可迭代,可切片的对象.事实上在幕后,Django使用了缓存技术..如果你真的需要一个列表,你可以强制对一个惰性对象取值:
querylist=list(Poll.objects.all())不过,最好不要这么做,尤其当一个结果集相当大时.由于Django要创建每一个对象的内存表示,这将占用相当大的内存.
结果集及其缓存行为每个结果集都包含一个cache.对一个新创建的结果集来说,缓存区是空的.当一个结果集第一次被取值,Django会进行一次数据库查询,并将查询结果放入缓存中,之后返回用户需要的数据.后面的取值操作会使用缓存中的数据而不用再次访问数据库.必须时刻记住:
结果集具有缓存行为.下面两行语句生成了两个临时的结果集,并进行了取值,之后舍弃:
print[pforpinPoll.objects.all()]#EvaluatetheQuerySet
print[pforpinPoll.objects.all()]#EvaluatetheQuerySetagain对一个小型的,低流量的站点来说,这不会造成严重问题.不过,对一个高访问量的站点来说,它双倍增加了数据库服务器的负担.另外,由于在两次操作之间可能有其它的用户增加或删除了投票,因此这两次操作得到结果可能并不相同.要避免这个问题,保存这个结果集并在后面重用该结果集:
queryset=Poll.objects.all()
print[pforpinqueryset]#Evaluatethequeryset
print[pforpinqueryset]#Re-usethecachefromtheevaluation专门的结果集取值函数下面这些函数也可以用来从一个结果集中取值.不同于迭代及切片操作,这些方法不具有缓存行为.每次使用这些函数,都会访问数据库.
get(**kwargs)以下文描述的"字段查询"格式返回匹配查找参数的对象.如果没有找到符合给定参数的对象,会引发一个模块级的DoesNotExist异常.如果找到不止一个对象,引发AssertionError异常.
count()返回结果集的行数.``count()``永远不会引发异常.根据你使用的数据库引擎(比如PostgreSQLvs.MySQL),它可能返回一个长整数而不是普通整数.
in_bulk(id_list)接受一个ID列表作为参数,返回一个字典(每个ID映射一个具有给定ID的对象实例).也接受可选的关键字查询参数(参数格式在下面"字段查询"小节有描述),这里有一个例子,使用上面定义的Pollmodel.>>>Poll.objects.in_bulk([1])
{1:
What'sup?
}
>>>Poll.objects.in_bulk([1,2])
{1:
What'sup?
2:
What'syourname?
}
>>>Poll.objects.in_bulk([])
{}latest(field_name=None)根据model的'get_latest_by'选项或可选的字段名参数返回最新的对象.例子:
>>>Poll.objects.latest()
What'sup?
>>>Poll.objects.latest('expire_date')
What'syourname?
关系(连接)当你在model中定义了一个关系字段(也就是,一个ForeignKey,OneToOneField,或ManyToManyField).Django使用关系字段的名字为model的每个实例添加一个描述符.在访问对象或关联对象时,这个描述符就象一个常规属性.举例来说,mychoice.poll会返回Choice实例对象关联的Poll对象.通过下面的关系,连接可以以非显式的方式进行:
choices.objects.filter(poll__slug="eggs")得到一个Choice对象列表,这些对象关联的Poll对象的slug字段值为eggs.允许多级连接.通过一个对象实例的便利函数(conveniencefunctions)就可直接查询该对象的关联对象.举例来说,如果p是一个Poll实例,p.choice_set()将返回所有关联的Choice对象列表.聪明的读者会注意到它等价于choices.objects.filter(poll__id=p.id),只是更加清晰.每一种关系类型会为关系中的每个对象自动创建一系列便利方法(类似choice_set()这样的方法).这些方法被双向创建,这样被关联的对象就不需要明确的定义反向关系,这一切都是自动完成的.
One-to-onerelationsone-to-one关系中的每个对象拥有一个get_relatedobjectname()方法.举例来说:
classPlace(meta.Model):
#...classRestaurant(meta.Model):
#...
the_place=meta.OneToOneField(places.Place)在上面的例子里,每个Place会自动拥有一个get_restaurant()方法,且每个Restaurant会自动拥有一个get_the_place()方法.
Many-to-onerelations在many-to-one关系中,关联对象(Many)会自动拥有一个get_relatedobject()方法.被关联的对象(one)会自动拥有get_relatedobject(),get_relatedobject_list(),和get_relatedobject_count()方法(功能与模块级的get_object(),filter(),和get_count()相同).在上面的民意测试例子里,一个Poll对象p自动拥有下列方法:
p.get_choice()
p.get_choice_list()
p.get_choice_count()Choice对象c则自动拥有下面的方法:
c.get_poll()Many-to-many关系Many-to-many关系类似`Many-to-onerelations`_,它生成同样的方法集.例外的是关联对象的get_relatedobject_list()方法返回一个实例的列表而不是一个仅一个实例.因此,若Poll和Choice是many-to-many关系,choice.get_poll_list()将返回一个列表.
专门的结果集除filter和exclude()之外,Django提供了一系列结果集处理方法,修改结果的类型,或修改sql查询在数据库执行的方式.
order_by(*fields)根据model中提供orderingtuple,结果集会被自动排序.不过,排序也可以通过order_by方法显式的进行:
Poll.objects.filter(pub_date__year=2005,
pub_date__month=1).order_by('-pub_date','question')结果集将按降序排列pub_date,然后按升序排列question."-pub_date"中的负号表示降序(递减).要取随机序,使用"?
",象下面这样:
Poll.objects.order_by=('?
')要按另一个表中的字段排序,添加另一个表的名字和一个句点,象下面这样:
Choice.objects.order_by=('Poll.pub_date','choice')无法指定排序是否大小写敏感,不管你的数据库后端如何排序,Django都会以大小写敏感的方式重新排序结果集..(这样是不是会降低效率?
不能关掉这个特性么?
)
distinct()默认的,一个结果集不会自动除去重复的行.尤其当你进行跨关系查询时,很容易出现重复的行.distinct()返回一个除去了重复行的新的结果集,它等价于SELECTDISTINCTSQL语句.
values(*fields)类似filter(),不过它返回一个字典的列表而不是model实例对象的列表.它接受一个可选参数:
fields,这是一个字段名列表或tuple.如果你没有指定fields,每个字段都会返回.否则就只返回你指定的字段名和值.这里有一个例子,使用上面定义的Pollmodel>>>fromdatetimeimportdatetime
>>>p1=Poll(slug='whatsup',question="What'sup?
",
...pub_date=datetime(2005,2,20),expire_date=datetime(2005,3,20))
>>>p1.save()
>>>