Model数据模型的检索查询

一旦创建了数据模型,我们可以利用django给我们提供的数据库抽象接口API来实现对象的创建,检索,更新或删除操作,使用非常方便。本文前提有以下数据模型:

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def __unicode__(self):
        return self.name

class Author(models.Model):
    name = models.CharField(max_length=50)
    email = models.EmailField()

    def __unicode__(self):
        return self.name

class Entry(models.Model):
    blog = models.ForeignKey(Blog)
    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 __unicode__(self):
        return self.headline

关于创建对象

        为了以python的方式来表示数据库表,django使用了一种可视化的系统:即model class表示一个数据库表,模型中一个类的实例表示数据库表中的一条记录。创建一个对象并实例化这个对象的过程就是给model class传递需要的关键参数,然后调用save()方法将其保存进数据库中。

       前提是需要根据python的路径将所需要的数据模型导入,假设模型在文件mysite/blog/models.py中,如下是例子:

>>> from blog.models import Blog
>>> b = Blog(name= 'Beatles Blog', tagline = 'All the latest Beatles news')
>>> b.save()

       在后台django将完成一个insert的sql语句,django不会去操作数据库直至显式地调用了save(),并且save()无返回值


ForeignKey和ManyToManyField字段的save操作

        更新一个ForeignKey字段的方式与保存一个正常的字段方式没有什么区别,简单的说,只需要通过右值赋值即可,下面例子中假如在数据库内已经保存着Entry和Blog实例数据,Entry的实例化对象entry内的blog属性被更新。

>>> from blog.models import Entry
>>> entry = Entry.objects.get(pk=1)
>>> cheese_blog = Blog.objects.get(name="Cheddar Talk")
>>> entry.blog = cheese_blog
>>> entry.save()
        而更新ManyToMany的方式稍微有些差异,在相应字段中它使用add()方法来添加一个记录至关系内,以下例子中将Author实例joe添加至entry对象:

>>> from blog.models import Author
>>> joe = Author.objects.create(name="Joe")
>>> entry.authors.add(joe)
        如果要一次性地添加多条记录至ManyToManyField关系中,可以在add()内放置多个参数即可:

>>> john = Author.objects.create(name="John")
>>> paul = Author.objects.create(name="Paul")
>>> george = Author.objects.create(name="George")
>>> ringo = Author.objects.create(name="Ringo")
>>> entry.authors.add(john,paul,george,ringo)


关于检索对象

        为了从数据库中检索对象,django会在model class上通过Manager管理器创建一个QuerySet,这个QuerySet表示从数据库中收集到的一组对象,这组对象进行0个,1个甚至多个filter过滤器筛选操作,只要给这个filter传递需要的条件参数即可。从SQL角度来看,一个QuerySet相当于一个SELECT语句,过滤筛选filter相当于WHERE或者LIMIT.

        通过使用模型的Manager管理器来获取QuerySet,每种model至少有一个Manager管理器,这个管理器也是"objects",可以直接通过model class来访问,如下:

>>> Blog.objects
<django.db.models.manager.Manager object at ...>    #所以Manager也是一种object,通过model class访问
>>> b = Blog(name='Foo', tagline='Bar')
>>> b.objects
Traceback:
    ...
AttributeError: "Manager isn't accessible via Blog instances."    #通过model class的实例不能访问Manager   
        注:Managers只能通过model class来访问,而不能通过model的实例化对象来访问,这主要是为了区分表级与记录级的操作。

        对model来说,Manager管理器是产生QuerSet的主要方式,如Blog.objects.all()返回数据库中包含所有Blog对象的一组QuerySet。

        1 检索所有的对象

        最简单的方式获取表中的对象的方法是直接获取表中的所有对象,要达到这一目的,可能在Manager中使用all()来获取

>>> all_entries = Entry.objects.all()
        all()方法返回了数据库中的所有包含对象的QuerySet.

        2 通过筛选器filter检索具体的对象

        有时,我们仅需要所有对象中的某一个子集。为了能够获得这个子集,我们可以提取出一个初始的QuerySet,然后再增加一个筛选条件,有两种常用的方式来提取一个新的Query:

        filter(**kwargs)              它返回一个新的QuerySet,并且它包含给定满足条件的对象

        exclude(**kwargs)        它返回一个新的QuerySet,并且它包含与给定条件不满足的对象

        至于筛选的条件参数,有一定的格式规则。下面会讲到。

         如下,为了获取一个QuerySet,其包含来自2006年的blog entries,使用filter():

Entry.objects.filter(pub_date__year=2006)
       这与这个是等价的:
Entry.objects.all().filter(pub_date__year=2006)
        (1) 链式筛选器filter

        提取一个新QuerySet的结果还是一个QuerySet,所以可以采用将其连接起来,如下:

>>> Entry.objects.filter(
...     headline__startswith='What'
... ).exclude(
...     pub_date__gte=datetime.date.today()
... ).filter(
...     pub_date__gte=datetime(2005, 1, 30)
... )
        初始时给出了数据库中所有的entries,然后添加一个filter,一个exclude,接着另一个filter,最终的QuerySet为以'What'开头,出版日期介于当前日期与2005.1.3之间的数据对象。

        (2) 筛选器过滤后产生的QuerySet是唯一的

每次你提取QuerySet后,会得到一个新的QuerySet,它不会与之前的QuerySet产生任何的关联,每次的提取操作都会生成一个独立且不同的QuerySet,它可以被保存,使用或复用。见如下例子:

>>> q1 = Entry.objects.filter(headline__startswith='What')
>>> q2 = q1.exclude(pub_date__gte=datetime.date.today())
>>> q3 = q1.filter(pub_date__gte=datetime.date.today())
这三个QuerySet分别都是独立的,第一个是基础的QuerySet,它包含所有的含有‘What'开头的数据,第二个是第一个的子集,排除了pub_date大于当前的记录,第三个也是第一个的子集,它的条件是选择那些大于今日的记录,而初始的QuerySet并未受到另两个QuerySet的影响。

        (3) QuerySet 是很懒的

        什么意思呢?说QuerySet比较懒,主要原因是创建这些QuerySet它并没有对数据库的任何的行为,即它不会真正的去数据库检索,产生数据。你可以花一天的时候不停的创建,都不会对数据库有任何影响。而当QuerySet被用于其它运算时,django才会真正的进行数据库的检索工作。可以看下面的例子:

>>> q = Entry.objects.filter(headline__startswith = 'What')
>>> q = q.filter(pub_date__lte=datetime.date.today())
>>> q = q.exclude(body_text__icontains="food")
>>> print(q)
        从表面看来,好像对数据库进行了三次操作,但实际上只进行了一次,且是在最后一句print,一般来说,产生QuerySet并不会真正影响到数据库,直至我们去获取它,而就在这时这些QuerySet才真正去访问数据库。

        

        3 用get检索单个对象

        filter()总是给出一个QuerySet,即使我们要匹配的对象只有一个,这时QuerySet只包含一个对象。如果我们事先已经知道要检索的对象只有一个时,可以在Manager管理器上使用get()方法来获取数据,它可以直接返回我们所需要的数据:

>>> one_entry = Entry.objects.get(pk=1)
        get()内的条件参数使用方法与filter及exclude()一致,有一定的格式,可以查阅相关资料

        请注意一点,get()和filter()两者之间是有一点儿区别的,如果对象只有一个,在使用filter()时,实际上用的是切片操作[0],只获取其第一个元素。如果没有结果被匹配,get()将返回一个"DoesNotExist"异常,这个异常是model class的一个属性。即在上面代码中,如果没有在Entry中没有一个pk=1的对象,django会触发一个Entry.DoesNotExist.

        类似地,如果用get()匹配的对象数据多于一个,django也会抱怨并触发一个MultipleObjectsReturned错误,它也是model class的其中一个属性。

        4 其它检索方法

        我们在大多数时候都是使用all(),get(),filter()和exclude()来从数据库中查找所需要的对象。但实际上还有其它更多的方法,这里不再说明,有需要再去查阅相关资料

        5 限集QuerySets

        可以使用python的切片操作来以修饰QuerySet成为一个有限集,这类似于SQL中的LIMIT以及OFFSET。如下例子,返回头5个对象:

>>> Entry.objects.all()[:5]
        下面则返回第6至第10个对象数据(OFFSET 5 LIMIT 5):

>>> Entry.objects.all()[5:10]
        但在QuerySet中,负向的索引是不支持的,如Entry.objects.all()[-1],。

        总的来说,用切片的方法对QuerySet进行操作将产生一个新的QuerySet,它也没有触发数据库的操作行为。但有一个特例就是,当在切片操作中使用了step,即“步长”时,会触发数据库的检索行为,如下所示,将从数据库中查到头10个对象当中的步长为2的对象:

>>> Entry.objects.all()[:10:2]
        若为了检索单个对象而不是一个list(如SELECT foo FROM bar LIMIT 1),可以用简单的索引操作来取代切片操作。如下返回排序后数据库的第一个Entry对象:

>>> Entry.objects.order_by("headline")[0]
        它与下面语句等价:

>>> Entry.objects.order_by("headline")[0:1].get()
        6 字段的查找条件
        字段的查找条件就是对QuerySet进行filter(),exclude()或get()中添加的条件参数,这与SQL当中的WHERE类似。基本的查找关键参数使用这个模式即可:

        field__lookuptype = value      (注意:双下划线),如下例子:

>>> Entry.objects.filter(pub_date__lte='2006-01-01')
        转成SQL语句就是:SELECT * from blog_entry WHERE pub_date <= '2006-01-01';

        在Django1.4中作出的更改:在查找条件中描述的字段必须是model中的字段,但是也有一个例外,即当那个字段是ForeignKey时,需要在添加后缀_id,在这种情况下,其条件的值必须是外键model中的主键值。如下例子:

>>> Entry.objects.filter(blog_id__exact = 4)
        “4”为blog model中的一个pk,如果传递的值无效,会触发TypeError.

       下面列举一些常用的查找类型:

        1 exact

>>> Entry.objects.get(headline__exact="Man bites dog")          
        等价于SQL语句: SELECT ... WHERE headline = 'Man bites dog';

        如果没有给出exact,django默认将使用exact,如下:

>>> Blog.objects.get(id__exact=14)  # Explicit form
>>> Blog.objects.get(id=14)         # __exact is implied
         2 iexact

        大小写不敏感的匹配,故查询:

>>> Blog.objects.get(name__iexact="beatles blog")
        它可以匹配到:"Beatles Blog", "BeAtlES BLOg"

         3 contains

         大小写敏感的匹配包含关系,如下:

Entry.objects.get(headline__contains="Lennon")
        相当于SELECT ... WHERE headline LIKE "%Lennon%";   它可以匹配到只要包含有Lennon的数据即可。

        大小写不敏感的还有icontains.

        4 startswitch, endswith

         同理,也有大小写不敏感的istartswith, iendswith

   

       (。。。。待续。。。。。) 

   












  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值