美文网首页
Django基础(三):models-database

Django基础(三):models-database

作者: 宇辰星君 | 来源:发表于2017-10-17 21:43 被阅读15次

    [TOC]

    模型与数据库:一一对应

    创建、查询操作

    注意Person.objects.xx()的返回值类型!

    # models.py
    class Person(models.Model):
        name = models.CharField(max_length=30)
        age = models.IntegerField()
    
    $ python manage.py shell
    In [1]: from learn.models import Person
    
    In [2]: Person.objects.create(name="suyn",age=26)
    Out[2]: <Person: Person object>
    In [3]: Person.objects.get(name="suyn")
    Out[3]: <Person: Person object>
    
    In [4]: import keyword
    In [5]: print keyword.kwlist  #打出所有的关键字
    ['and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'exec', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'not', 'or', 'pass', 'print', 'raise', 'return', 'try', 'while', 'with', 'yield']
    

    查询结果中显示<Person: Person object>,这里并没有显示出与suyn的相关信息,如果用户多了就无法知道查询出来的到底是谁,查询结果是否正确,我们重新修改models.py。

    注:name 和 age 等字段中不能有__和关键字

    双下划线,在Django QuerySet API中有特殊含义:用于关系,包含,不区分大小写,以什么开头或结尾,日期的大于小于,正则等;name 是合法的,student_name 也合法,但是student__name不合法。

    # models.py
    class Person(models.Model):
        name = models.CharField(max_length=30)
        age = models.IntegerField()
    
        def __unicode__(self):
            return self.name
    $ python manage.py shell
    In [1]: from learn.models import Person
    
    In [2]: Person.objects.get(name="suyn")
    Out[2]: <Person: suyn>  #get方法返回一个Person对象,返回多个要用filter/exclude/all
    
    In [3]: p = Person(name="sophia",age=20)
    In [4]: Person.objects.all()
    Out[4]: <QuerySet [<Person: suyn>]>  #all方法返回QuerySet一个集合,像列表
    In [5]: p.save()  #保存后才真正更新到数据库
    In [6]: Person.objects.all()
    Out[6]: <QuerySet [<Person: suyn>, <Person: sophia>]>
    
    In [7]: p = Person(name="HSZ")
    In [9]: p.age=18
    In [11]: p.save()  #所有必须非空属性有值才可以保存
    In [12]: Person.objects.all()
    Out[12]: <QuerySet [<Person: suyn>, <Person: sophia>, <Person: HSZ>]>
    
    ## get_or_create方法:防止重复,但速度要相对慢些,返回一个元组,第一个为Person对象,第二个为True或False, 新建时返回的是True, 已经存在时返回False.
    In [13]: Person.objects.get_or_create(name="LJ", age=23)
    Out[13]: (<Person: LJ>, True)
    In [2]: Person.objects.get_or_create(name="LJ", age=20)
    Out[2]: (<Person: LJ>, True)
    In [3]: Person.objects.get_or_create(name="LJ", age=20)
    Out[3]: (<Person: LJ>, False)
    
    ## 获取对象的方法get/filter/exclude/all等
    ## 先查看数据库预览
    mysql> select * from learn_person;
    +----+--------+-----+
    | id | name   | age |
    +----+--------+-----+
    |  1 | suyn   |  26 |
    |  2 | sophia |  20 |
    |  3 | HSZ    |  18 |
    |  4 | LJ     |  23 |
    |  5 | LJ     |  20 |
    +----+--------+-----+
    5 rows in set (0.03 sec)
    
    In [4]: Person.objects.all()
    Out[4]: <QuerySet [<Person: suyn>, <Person: sophia>, <Person: HSZ>, <Person: LJ>, <Person: LJ>]>
    
    In [5]: Person.objects.all()[:2]
    Out[5]: <QuerySet [<Person: suyn>, <Person: sophia>]>
    
    In [6]: Person.objects.filter(name="LJ") #等于
    Out[6]: <QuerySet [<Person: LJ>, <Person: LJ>]>
    In [7]: Person.objects.filter(name__exact="LJ") #跟name="LJ"一样
    Out[7]: <QuerySet [<Person: LJ>, <Person: LJ>]>
    In [8]: Person.objects.filter(name__iexact="lj") #不区分大小写
    Out[8]: <QuerySet [<Person: LJ>, <Person: LJ>]>
    
    In [9]: Person.objects.filter(name__regex="^s") #正则查询
    Out[9]: <QuerySet [<Person: suyn>, <Person: sophia>]>
    In [10]: Person.objects.exclude(name__regex="^s") #exclude与filter相反,排除
    Out[10]: <QuerySet [<Person: HSZ>, <Person: LJ>, <Person: LJ>]>
    

    filter的一些常用过滤条件:
    __exact __iexact
    __contains __icontains
    __regex __iregex

    由上总结QuerySet API

    从数据库中查询出来的结果一般是一个集合,这个集合叫做 QuerySet。

    1. QuerySet创建对象的四中方法
      前三种方法返回的都是对应的 object(即Author对象),最后一种方法返回的是一个元组
    # 方法 1
    Author.objects.create(name="WeizhongTu", email="tuweizhong@163.com")
     
    # 方法 2
    twz = Author(name="WeizhongTu", email="tuweizhong@163.com")
    twz.save()
     
    # 方法 3
    twz = Author()
    twz.name="WeizhongTu"
    twz.email="tuweizhong@163.com"
    twz.save()
     
    # 方法 4,首先尝试获取,不存在就创建,防止重复 # 返回值(object, True/False)
    Author.objects.get_or_create(name="WeizhongTu", email="tuweizhong@163.com")
    
    1. QuerySet获取对象的方法
    Person.objects.all() # 查询所有
    Person.objects.all()[:10] 切片操作,获取10个人,切片可以节约内存,不支持负索引(Negative indexing is not supported.)
    # 解决负索引问题:
    In [16]: Person.objects.order_by('id')[:2]
    Out[16]: <QuerySet [<Person: suyn>, <Person: sophia>]>
    In [18]: Person.objects.order_by('-id')[:2]
    Out[18]: <QuerySet [<Person: LJ>, <Person: LJ>]>
    
    Person.objects.get(name="WeizhongTu") # 名称为 WeizhongTu 的一条,多条会报错
     
    get是用来获取一个对象的,如果需要获取满足条件的一些人,就要用到filter
    Person.objects.filter(name="abc") # 等于Person.objects.filter(name__exact="abc") 名称严格等于 "abc" 的人
    Person.objects.filter(name__iexact="abc") # 名称为 abc 但是不区分大小写,可以找到 ABC, Abc, aBC,这些都符合条件
     
    Person.objects.filter(name__contains="abc") # 名称中包含 "abc"的人
    Person.objects.filter(name__icontains="abc") #名称中包含 "abc",且abc不区分大小写
     
    Person.objects.filter(name__regex="^abc") # 正则表达式查询
    Person.objects.filter(name__iregex="^abc")# 正则表达式不区分大小写
     
    # filter是找出满足条件的,当然也有排除符合某条件的
    Person.objects.exclude(name__contains="WZ") # 排除包含 WZ 的Person对象
    Person.objects.filter(name__contains="abc").exclude(age=23) # 找出名称含有abc, 但是排除年龄是23岁的
    
    ## 支持链式查询
    Author.objects.filter(name__contains="WeizhongTu").filter(email="tuweizhong@163.com")
    Author.objects.filter(name__contains="Wei").exclude(email="tuweizhong@163.com")
    Person.objects.filter(name__contains="abc").exclude(age=23)
    
    1. QuerySet可迭代
    In [1]: from learn.models import Entry
    # 迭代Entry对象
    In [10]: es = Entry.objects.all()
    In [11]: for e in es:  
        ...:     print e.headline
        ...:     
    about suyn's personal blog
    about lj's wonderful life
    
    In [2]: Entry.objects.all()
    Out[2]: <QuerySet [<Entry: about suyn's personal blog>, <Entry: about lj's wonderful life>]>
    
    In [3]: Entry.objects.all().exists()  #检查 Entry 中是否有对象
    Out[3]: True
    
    # 获取Entry数量
    In [4]: len(Entry.objects.all())
    Out[4]: 2
    
    In [5]: Entry.objects.count()  #推荐用此
    Out[5]: 2
    
    In [6]: list(Entry.objects.all())  #强行将 QuerySet 变成 列表
    Out[6]: [<Entry: about suyn's personal blog>, <Entry: about lj's wonderful life>]
    
    #查询结果排序
    Author.objects.all().order_by('name')
    Author.objects.all().order_by('-name') # 在 column name 前加一个负号,可以实现倒序
    
    1. QuerySet 重复的问题,使用 .distinct() 去重

    一般的情况下,QuerySet 中不会出来重复的,重复是很罕见的,但是当跨越多张表进行检索后,结果并到一起,可以会出来重复的值(我最近就遇到过这样的问题)

    qs1 = Pathway.objects.filter(label__name='x')
    qs2 = Pathway.objects.filter(reaction__name='A + B >> C')
    qs3 = Pathway.objects.filter(inputer__name='WeizhongTu')
     
    # 合并到一起
    qs = qs1 | qs2 | qs3
    这个时候就有可能出现重复的
     
    # 去重方法
    qs = qs.distinct()
    
    1. QuerySet 是可以用pickle序列化到硬盘再读取出来的
    >>> import pickle
    >>> query = pickle.loads(s)     # Assuming 's' is the pickled string.
    >>> qs = MyModel.objects.all()
    >>> qs.query = query            # Restore the original 'query'.
    

    数据表更改

    Django 1.7.x 及以后的版本集成了 South 的功能,自动发现需要更改的,应用到数据库中去。Django 的第三方 app South 就是专门做数据库表结构自动迁移工作,它现在已经俨然成为 Django 事实上的数据库表迁移标准,很多第三方 app 都会带 South migrations 脚本。

    自定义Field

    • 减少文本的长度,保存数据的时候压缩,读取的时候解压缩,如果发现压缩后更长,就用原文本直接存储:
      from_db_value 函数用于转化数据库中的字符到 Python的变量,
      to_python 函数用于转化数据库中的字符到 Python的变量,
      get_prep_value 用于将Python变量处理后(此处为压缩)保存到数据库,使用和Django自带的 Field 一样。
      方法重写没有在源码中找到合适的,待修改???

    • 保存一个列表到数据库中,在读取用的时候要是 Python的列表的形式,我们来自己写一个 ListField:
      ???不理解

    相关文章

      网友评论

          本文标题:Django基础(三):models-database

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