美文网首页
Django的ORM

Django的ORM

作者: 戴维得 | 来源:发表于2017-10-06 13:04 被阅读0次

    Django查询集是写在model或者view文件里面,对数据库进行增删改查,其实就是封装了MySQL的语句,使其变得简单易学,但是查询集可能还是解决不了全部问题,如果遇到查询集解决不了的情况,应该使用MySQL语句进行操作

    添加数据库内容,包括建立模型(创建数据表),创建对象(添加每行内容),保存对象的改动(修该内容),添加外键

    建立模型

    一旦你建立好数据模型,Django 会自动为你生成一套数据库抽象的API,可以让你创建、检索、更新和删除对象。这篇文档阐述如何使用这些API。

    首先建立如下模型,这是一个图书管理应用,图书和作者是一个多对多的关系:

    from django.db import models
    # Create your models here.
    
    class Author(models.Model):
        name = models.CharField(max_length=32)
        sex = models.CharField(max_length=32)
        age = models.IntegerField()
        
        def __str__(self):
            return self.name
    
    class Book(models.Model):
        title = models.CharField(max_length=32)
        price = models.IntegerField()
        date = models.DateField()
        publish = models.CharField(max_length=32)
        author = models.ManyToManyField(Author)
        
        def __str__(self):
            return self.title
    

    创建对象

    Django 使用一种直观的方式把数据库表中的数据表示成Python 对象:一个模型类代表数据库中的一个表,一个模型类的实例代表这个数据库表中的一条特定的记录。

    创建对象有两种方法:

    • 使用关键字参数实例化模型实例来创建一个对象,然后调用save()把他保存到数据库中

      a = Author(name='alex', sex='male', age=4)
      a.save()

    • 使用create方法

      Author.objects.create(name='yuan', sex='male', age=8)

    保存对象的改动

    假设Blog 的一个实例b5 已经被保存在数据库中,下面这个例子将更改它的name 并且更新数据库中的记录:

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

    保存字段

    保存ForeignKey字段

    • 保存ForeignKey字段的方式和保存普通字段相同,只要把一个正确类型的对象赋值给该字段
    • 更改后save()保存

    保存ManyToMany字段

    更新ManyToManyField的方式有一些不同,需要使用字段的add()方法来增加关联关系的一条记录,

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

    注意:取对象的时候要拿id取

    • 先给两个表分别实例化对象生成每一行数据
    • 然后在外面先分别选取需要添加关系的对象
    • 然后给有外键字段的对象add另一个,也可以add多个

    查主要是对数据库的搜索查询,找到适合条件的数据可以通过模型中的管理器构造一个查询集,来从你的数据库总获取对象。

    获得所有对象

    获得一个表中所有的对象的最简单的方式是全部获取,可以使用管理器的all()方法

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

    获取一个单一对象

    过滤器始终会给你一个查询集,即使只有一个对象满足条件,你如果只想查询一个的话,可以使用get方法,他直接返回该对象

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

    使用过滤器获取特定对象集

    • all()方法返回了一个包含数据库表中所有记录查询集。但在通常情况下,你往往想要获取的是完整数据集的一个子集。
    • filter(**kwargs)返回一个新的[查询集,它包含满足查询参数的对象。
    • exclude(**kwargs)返回一个新的查询集,它包含不满足查询参数的对象。

    比如要获取年份为2006的所有文章的查询集,可以使用filter()方法

    Entry.objects.filter(pub_date__year=2006)
    

    相当于

    Entry.objects.all().filter(pub_date__year=2006)
    
    • 查询集的筛选结果本身还是查询集,所以可以将筛选语句链接在一起
    • 每次筛选一个查询集,得到的都是全新的另一个查询集,它和之前的查询集之间没有任何绑定关系每次筛选都会创建一个独立的查询集,它可以被存储以及反复使用。
    • 查询集是惰性执行的,创建查询集不会带来任何数据库的访问,直到查询集需要求值时,Django才会真正运行这个查询。

    限制查询集

    可以使用切片语法来限制查询集

    下面语法返回前面5个对象

    >>> Entry.objects.all()[:5]
    

    下面语句返回6到10个对象

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

    它不支持负的索引

    通常,查询集的切片返回一个新的查询集—— 它不会执行查询。有一个例外,是如果你使用Python 切片语法中"step"参数。例如,下面的语句将返回前10 个对象中每隔2个对象,它将真实执行查询:

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

    如果要选取一个单一的对象而不是列表,则使用索引

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

    字段查询

    字段查询广泛应用于filter(),exclude()和get()的关键字参数指定

    查询的关键字参数的基本形式是 field__lookuptype=value,其中field为字段,lookuptype是匹配样式,value为值

    如果要涉及到外键参数过滤,形式应该为 class__field__lookuptype=value,其中class为表名

    gt 大于

    ltn 小于

    exact 精确匹配

    例如:

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

    将生成下面的SQL:

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

    iexact大小写不敏感的匹配。

    所以,查询:

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

    将匹配标题为"Beatles Blog"、"beatles blog" 甚至"BeAtlES blOG" 的Blog。

    contains大小写敏感的包含关系测试

    Entry.objects.get(headline__contains='Lennon')
    

    大体可以翻译成下面的SQL:

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

    Icontains大小写不敏感的包含关系测试

    startswith,endswith

    分别表示以XXX开头和以XXX结尾。

    跨关联关系的查询

    若要跨越关联关系,只需要使用关联的模型字段的名称,并使用双下划线分隔,直到你想要的字段,这种跨越可以是任意的深度,

    下面这个例子获取所有Blog 的name 为'Beatles Blog' 的Entry 对象:

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

    它还可以反向工作,若要引用一个反向的关系,只需要使用该模型的小写的名称

    下面的示例获取所有的Blog 对象,它们至少有一个Entry 的headline 包含'Lennon':

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

    分组查询

    如果要查询所有书籍的平均价格

    from django.db.models import Avg,Min,Sum,Max
    # 求所有书籍的平均价格
    ret=Book.object.all().aggregate(Avg('price'))
    

    分组使用value()来分组

    F() 对象:引用模型的字段

    假设要将所有的书的价格改为1000,可以使用如下语句

    Book.object.filter(id=5).update(price=1000)
    

    但是,如果要给每本书的价格价格加20,这就涉及到如何取得前面的价格,这就用到了F对象

    from django.db.models import F,Q
    Book.object.all().update(price=F('price')+20)
    

    Q对象精确查找

    如果要查询书籍中名字的来头为'"老"字,且价格大于100的书籍,应该这样

    ret = Book.object.filter(title__startwith='老',price__gt=100)
    print(ret)
    

    但是如果要查询书籍中名字的开头为"老"字,或者价格大于100的书,用逗号就没法完成,这就用到了Q对象

    from django.db.models import F,Q
    et = Book.object.filter(Q(title__startwith='老') | Q(price__gt=100)
    

    Q对象可以使用 & | 以及 ~分别代表,and,or和not用法

    访问关联的对象

    模型的实例可以很方便的进行关联对象的查询

    一对多关系

    正向查询

    如果一个模型具有ForeignKey,那么该模型的实例将可以通过属性访问关联的(外部)对象。

    例如:

    >>> e = Entry.objects.get(id=2)
    >>> e.blog # Returns the related Blog object.
    

    对外键的修改如下

    >>> e = Entry.objects.get(id=2)
    >>> e.blog = some_blog
    >>> e.save()
    

    反向查询

    反向查询使用foo_set管理器,其中,foo为源模型的小写名称

    比如

    >>> b = Blog.objects.get(id=1)
    >>> b.entry_set.all() # Returns all Entry objects related to Blog.
    
    # b.entry_set is a Manager that returns QuerySets.
    >>> b.entry_set.filter(headline__contains='Lennon')
    >>> b.entry_set.count()
    

    你可以在ForeignKey定义时设置related_name参数来覆盖foo_set 的名称。例如,如果Entry 模型改成blog = ForeignKey(Blog, related_name='entries'),那么上面的示例代码应该改成这样:

    >>> b = Blog.objects.get(id=1)
    >>> b.entries.all() # Returns all Entry objects related to Blog.
    
    # b.entries is a Manager that returns QuerySets.
    >>> b.entries.filter(headline__contains='Lennon')
    >>> b.entries.count()
    

    处理关联对象的其他方法

    add(obj1, obj2, ...)

    添加一指定的模型对象到关联的对象集中。

    create(**kwargs)

    创建一个新的对象,将它保存并放在关联的对象集中。返回新创建的对象。

    remove(obj1, obj2, ...)

    从关联的对象集中删除指定的模型对象。

    clear()

    从关联的对象集中删除所有的对象。

    多对多关系

    多对多关系的两端都会自动获得访问另一端的API。这些API 的工作方式与上面提到的“方向”一对多关系一样。

    唯一的区别在于属性的名称:定义 ManyToManyField的模型使用该字段的属性名称,而“反向”模型使用源模型的小写名称加上'_set' (和一对多关系一样)。

    一个例子可以让它更好理解:

    # 正向查询
    e = Entry.objects.get(id=3)
    e.authors.all() # Returns all Author objects for this Entry.
    e.authors.count()
    e.authors.filter(name__contains='John')
    
    # 反向查询
    a = Author.objects.get(id=5)
    a.entry_set.all() # Returns all Entry objects for this Author.
    

    一对一关系

    一对一关系与多对一关系非常相似。如果你在模型中定义一个OneToOneField,该模型的实例将可以通过该模型的一个简单属性访问关联的模型。

    例如:

    class EntryDetail(models.Model):
        entry = models.OneToOneField(Entry)
        details = models.TextField()
    
    ed = EntryDetail.objects.get(id=2)
    ed.entry # Returns the related Entry object.
    

    在“反向”查询中有所不同。一对一关系中的关联模型同样具有一个管理器对象,但是该管理器表示一个单一的对象而不是对象的集合:

    e = Entry.objects.get(id=2)
    e.entrydetail # ret
    

    改(update())

    修改的方式比较简单,使用update对象

    比如要修改id为5的书的价格为1000

    Book.object.filter(id=5).update(price=1000)
    

    如果要一次性修改多个对象

    # Update all the headlines with pub_date in 2007.
    Entry.objects.filter(pub_date__year=2007).update(headline='Everything is the same')
    

    删(delete())

    例如,下面的语句删除pub_date 为2005 的所有Entry对象

    Entry.objects.filter(pub_date__year=2005).delete()
    

    注意,当Django要删除一个对象时,任何有外键指向要删除对象的对象将一起被删除

    相关文章

      网友评论

          本文标题:Django的ORM

          本文链接:https://www.haomeiwen.com/subject/hxnlyxtx.html