zoukankan      html  css  js  c++  java
  • django学习之Model(三)QuerySet

    接下来主要学习Models中的Making queries

    写好models.py后,django会自动提供一个数据库的抽象API,来实现CRUD(create, retrieve, update, delete)。这一部分主要就是怎样去用这些API。在data model reference会有全部的讲解。

    接下来都会反复用到下边这个例子,或者在这段代码上进行扩展:

    from django.db import models
    
    class Blog(models.Model):
        name = models.CharField(max_length=100)
        tagline = models.TextField()
    
        # On Python 3: def __str__(self):
        def __unicode__(self):
            return self.name
    
    class Author(models.Model):
        name = models.CharField(max_length=50)
        email = models.EmailField()
    
        # On Python 3: def __str__(self):
        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()
    
        # On Python 3: def __str__(self):
        def __unicode__(self):
            return self.headline

    1-创建对象

    一个model class 对应生成一个database table,一个class的实例就对应存进database table中的一个记录。class中的field对应这table中的column.

    调用python语法中的怎样给类的对象赋值的语法,然后在调用对象的.save()函数,就创建了一条数据。

    假设mysite/blog/models.py,下例:

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

     python语法中的赋值对应SQL的INSERT语句,只有调用save()的时候,django才对database进行了操作。并且save()没有返回值。如果把create和save用一条语句实现,create()方法可以实现。

    2-保存对数据的修改

    也是用save()实现。即重新赋值,重新save:

    >>> b5.name = 'New name'
    >>> b5.save()

    这相当于SQL中的UPDATE, save()

    3-保存ForeignKey和ManyToManyField 的fields

    update ForeignKey和update普通field是一样的操作,从python角度来讲,就是把一个object赋值给另一个类中的object类型的变量。

        blog = models.ForeignKey(Blog)#相当于blog是一个存放Blog的实例(对象)的一个变量。

     但是在update ManyToManyField的时候,用的是add()方法,且不用save()

    >>> from blog.models import Author
    >>> joe = Author.objects.create(name="Joe")
    >>> entry.authors.add(joe)

     也可一进行批量操作:

    >>> 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)

    注意类型要匹配,不能把author add到blog中,这样django会报错。

    4-检索对象(Retrieving objects)

    通过Manager来在model class上建立QuerySet (查询)。QuerySet展示出database中的数据。filters可有可无,filters顾名思义,就是用来过滤,或者说筛选。在SQL中,QuerySet相当于SELECT语句,filters相当于WHERE或LIMIT。可以从model的Manager中获得QuerySet,每个model都有一个Manager,默认使用的是objects.默认的是通过model class来实现,注意下面的代码:

    >>> Blog.objects
    <django.db.models.manager.Manager object at ...>
    >>> b = Blog(name='Foo', tagline='Bar')
    >>> b.objects
    Traceback:
        ...
    AttributeError: "Manager isn't accessible via Blog instances."

    用的是Blog.objects, 而不是通常感觉上的对象的方法,因为manager是class的,而不是object的。官方文档说,这种Manager的设计,加强了table-level与record-level操作的分离。可以理解为,整个django更好的实现了起框架的作用,就是不管具体的instance是啥样的,而只注意在框架的设计上,让其普遍适用于各种instance.

    1)-最简单的检索database table的对象的方法,就是all,全检索。在Manager上用all():

    >>> all_entries = Entry.objects.all()

    all()方法返回了一个QuerySet,包含database中所有的数据对象。

    2)-稍微复杂点的就是加上filters来过滤出想要的结果。

    常用的有2种:

    a)-filter(**kwargs)   返回值为满足参数所表达的条件的QuerySet

    b)-exclude(**kwargs)   返回值QuerySet剔除了(exclude)参数所表达的条件的数据。

    分别有如下2例:

    Entry.objects.filter(pub_date__year=2006)#年代为2006年的被返回
    Entry.objects.all().filter(pub_date__year=2006)#剔除2006年的,其他剩下的被返回

    3)-链式filters

    相当于级联式的,看代码就明白了:

    >>> Entry.objects.filter(
    ...     headline__startswith='What'
    ... ).exclude(
    ...     pub_date__gte=datetime.date.today()
    ... ).filter(
    ...     pub_date__gte=datetime(2005, 1, 30)
    ... )

    4)-filter后的QuerySet是唯一且不变的

    下面代码中的q1,q2,q3是独立互不影响的:

    >>> 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())

    5)-QuerySet很懒

    直到你确实要用到值的时候,QuerySet才去database读取数据,下面代码中就是在print(q)的时候才读database的:(具体解释见When QuerySets are evaluated

    >>> 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)#hit the database

    6)-可以用get方法检索一个数据

    >>> one_entry = Entry.objects.get(pk=1)

    get()和filter()还是有区别的,如果没有可以匹配的query,则get()会放回一个DoseNotExist的错误,这个exception是model class的一个参数。相似的,如果是有多个数据匹配get(),则会出现MultipleObjectReturned的错误。

    7)-其他的QuerySet方法

    完整的方法介绍在这里QuerySet API Reference 

    选前5个数据:

    >>> Entry.objects.all()[:5]
    >>> Entry.objects.all()[5:10]#从第6个到第10个

    通常对QuerySet进行切片会返回一个新的QuerySet,有一个例外就是,如果用python中的step切片语法,就会对原QuerySet进行处理然后得到一个新的QuerySet:

    >>> Entry.objects.all()[:10:2]

    以下两句是相同的:

    >>> Entry.objects.order_by('headline')[0]
    >>> Entry.objects.order_by('headline')[0:1].get()

    8)-Field lookups

    在QuerySet的方法(filter,get,exclude)的参数列表中加入Field lookups作为限制条件:

    >>> Entry.objects.filter(pub_date__lte='2006-01-01')

    相当于SQL:

    SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01';

     思考:python能够定义一个函数,是它接收正在运行计算中的变量,更多的理解移步python官网:Keyword Arguments 

    一般在lookups中的都是用field名的,有一种情况例外,ForeignKey,可以在field名字后面加上 _id , 后面的值是这个外部model的id值:

    >>> Entry.objects.filter(blog_id__exact=4)

    若传个不存在的关键字,lookup函数会产生TypeError的错误。

    database API有很多lookup类型,完备的资料在这里:field lookup reference. 下面来看一些常用的例子:

    exact

    >>> Entry.objects.get(headline__exact="Man bites dog")

    相当于SQL

    SELECT ... WHERE headline = 'Man bites dog';

    iexact

    >>> Blog.objects.get(name__iexact="beatles blog")

    SQL

    SELECT ... WHERE headline LIKE '%Lennon%';

    相似的还有icontains

    还有startswithendswith等方法,全部的方法得去这里了field lookup reference.

    9)-Lookups 能够拓展relationships

    django有一个强大且直观的方法来处理数据的relationships,可以自动的帮助你处理SQL中的JOINs操作。使用很简单,只需要用跨model的相关的field的名称,然后用双下划线 __来连接就行了。下例中是获得所有的Entry的数据,条件是Entry中的Blog参数的名字是“Beatles Blog”:

    >>> Entry.objects.filter(blog__name__exact='Beatles Blog')

    这种span可以任意深的去关联数据。也可以反向来用,例如从Blog中反向找entry:

    >>> Blog.objects.filter(entry__headline__contains='Lennon')

    如果要用filter去处理多个关系的时候,而且中间的某个model没有满足filter的条件,那么,lookup不会报错,而是会认为这个中间的model的field是空的(NULL值),但是是存在的。例如:

    Blog.objects.filter(entry__authors__name='Lennon')

    如果没有author跟entry连接,lookup不会报错,他会认为有一个空值的entry的。但是如果你明确指定了,如下:

    Blog.objects.filter(entry__authors__name__isnull=True)

    那就会返回这样满足条件的Blog了,说明他存在嘛。

    如果你不想要这种结果,那就应该这样写:

    1 Blog.objects.filter(entry__authors__isnull=False,
              entry__authors__name__isnull=True)

    注意以上两种的区别,一个是不存在的,一个是确实存在而且想过滤掉某些干扰数据的。

    今天先到这儿!

  • 相关阅读:
    min25筛
    ngnix安装
    Sublime Text 添加到右键菜单 带菜单图标
    临界区与竟态条件
    cscope 支持C++项目
    内网信息收集
    域权限维持-Hook PasswordChangeNotify
    域权限维持-SID History
    域权限维持-DSRM
    ZooKeeper
  • 原文地址:https://www.cnblogs.com/ee2213/p/3914620.html
Copyright © 2011-2022 走看看