Model数据模型的检索查询

[复制链接]

1234

主题

-8

回帖

216

积分

游客

积分
216
a420995601 发表于 2018-12-23 03:39:16 | 显示全部楼层 |阅读模式
  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
   #所以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

你喜欢看
  • python如何操作Sql Server 2008

      python如何操作Sql Server 2008   最近由于公司的一个项目需要,需要使用Sql Server 2008数据库,开 ...

  • linux内核如何管理进程

      linux内核如何管理进程   “进程”有诸多的定义,在许多的教材资料上,其定义是一个程序的执行实例, ...