day 05 models进阶

1.models基本操作

 
django中遵循 Code Frist 的原则,即:根据代码中定义的类来自动生成数据库表。
对于ORM框架里:
    我们写的类表示数据库的表
    如果根据这个类创建的对象是数据库表里的一行数据
    那么对象.属性(对象.id 对象.value)就是每一行里的某个字段数据 
    
models基本操作
增:
    1)创建对象实例,然后调用save方法:
         obj = Author() 
         obj.first_name = 'zhang'
         obj.last_name = 'san'
        obj.save()
     2)创建对象并初始化,再调用save方法:
        obj = Author(first_name='zhang', last_name='san') 
        obj.save()
    3)使用create方法
        Author.objects.create(first_name='li', last_name='si')
    4)使用get_or_create方法,可以防止重复
        Author.objects.get_or_create(first_name='zhang', last_name='san')
    
        
删:
    使用Queryset的delete方法:
    # 删除指定条件的数据
    Author.objects.filter(first_name='zhang').delete()
    # 删除所有数据
    Author.objects.all().delete() 
    注意: objects不能直接调用delete方法。
    使用模型对象的delete方法:
    obj = Author.objects.get(id=5)
    obj.delete()
    
改:
Author.objects.filter(last_name='dfdf').update(last_name='san')
    模型没有定义update方法,直接给字段赋值,并调用save,能实现update的功能,比如:
    >>> obj = Author.objects.get(id=3)
    >>> obj.first_name = 'zhang'
    >>> obj.save()
    save更新时会更新所有字段。如果只想更新某个字段,减少数据库操作,可以这么做:
    obj.first_name = 'li'
    obj.save(update_fields=['first_name'])
查:
    获取单条数据:Author.objects.get(id=123)
    get():返回一个满足条件的对象
        如果没有找到符合条件的对象,会引发模型类.DoesNotExist异常
        如果找到多个,会引发模型类.MultipleObjectsReturned 异常
    first():返回查询集(QuerySet)中的第一个对象
    last():返回查询集中的最后一个对象
    count():返回当前查询集中的对象个数
    exists():判断查询集中是否有数据,如果有数据返回True没有反之
    >>> Author.objects.all()               # 获取全部
    >>> Author.objects.filter(name='seven') # 获取指定条件的数据
    >>> Author.objects.all().values('password') # 获取指定列的值,可以传多个参数!返回包含字典的列表(保存了字段名和对应的值)
        Author.objects.all().values_list('password') # 获取指定列的值,可以传多个参数!返回包含元组列表(只保存值)
        
        
    进阶操作:
        # 获取个数
        Author.objects.filter(name='seven').count()
            
        Author.objects.filter(id__gt=1)      # 获取id大于1的值    
        # select * from Author where id > 1
        
        Author.objects.filter(id__gte=1)     # 获取id大于或等于1的值
        # select * from Author where id >= 1  
        
        Author.objects.filter(id__lt=10)     # 获取id小于10的值        
        # select * from Author where id < 10
        
        Author.objects.filter(id__lte=10)    # 获取id小于等于或d10的值   
        # select * from Author where id <= 10
    
        Author.objects.filter(id__lt=10, id__gt=1)   # 获取id大于1 且 小于10的值   
        # select * from Author where id < 10 and id > 1
        
        Author.objects.filter(id__in=[11, 22, 33])   # 获取id在11、22、33中的数据        
        # select * from Author where id in (11,22,33)
        
        Author.objects.exclude(id__in=[11, 22, 33])  # not in        
        # select * from Author where id not in (11,22,33)
        Author.objects.filter(name__contains="ven")  # contains(和数据库中like语法相同)        
        # select * from Author where name like '%ven%'
        
        Author.objects.filter(name__icontains="ven") # icontains大小写不敏感     
        
         Author.objects.filter(name__regex="^ven")  # 正则匹配
         Author.objects.filter(name__iregex="^ven") # 正则匹配,忽略大小写
        Author.objects.filter(id__range=[1, 2])   # 范围bettwen and
        
         # startswith,istartswith, endswith, iendswith: 
         #  以什么开始,以什么结束,和上面一样带i的是大小写不敏感的, 其实不带i的也忽略大小写
        
        Author.objects.filter(name='seven').order_by('id')    # asc正序
        Author.objects.filter(name='seven').order_by('-id')   # desc反序
        Author.objects.all()[10:20]  # 切片,取所有数据的10条到20条,分页的时候用的到,下标从0开始,不能为负数
        
        # 分页
        page = 1
        per_number = 3
        
        start = (page-1) * per_number
        end = start + per_number
        [start:end]
        
# 聚合
    使用aggregate()函数返回聚合函数的值
        Avg:平均值
        Count:数量
        Max:最大
        Min:最小
        Sum:求和
    from django.db.models import Count, Min, Max, Sum
    Author.objects.aggregate(Max('age'))
# 注解
    obj = Author.objects.annotate(num_books=Count('book'))
    obj[0].num_books
 

2. 模块关联关系

关系
    ·分类
        ·ForeignKey:一对多,将字段定义在多的端中
        ·ManyToManyField:多对多,将字段定义在两端中
        ·OneToOneField:一对一,将字段定义在任意一端中
                
        
一对多关系,举例说明(一对一, 多对多类似): 
        一个班级可以有多个学生, 一个学生只能属于一个班级
        class Grade(models.Model):
            name = models.CharField(max_length=20)
        class Student(models.Model):
             name = models.CharField(max_length=20)
             grade = models.ForeignKey(Grade)
     
        对象的使用:
            正向(在Student这边,有grade属性的这一边):
                获取学生所在班级(对象): stu.grade
                获取学生所在班级的属性: stu.grade.name
            反向(在Grade这边):
                获取班级的所有学生(获取Manager对象):grade.student_set
               获取班级的所有学生(获取QuerySet查询集): grade.student_set.all()
                
        filter(),get()等操作中的使用:
            正向(在Student这边,有grade属性的这一边):
                    Student.objects.filter(属性__name=1)
                如:Student.objects.filter(grade__name=1)
            反向(在Grade这边):
                    Grade.objects.filter(类名小写__id=7)
                如:Grade.objects.filter(student__id=7)
        
 

3. Model连表结构

ORM核心知识回顾:
    django根据代码中定义的类来自动生成数据库表。
    我们写的类表示数据库的表。
    根据这个类创建的对象是数据库表里的一行数据。
    对象.id 对象.value 是每一行里的字段数据
一对多:models.ForeignKey(其他表)
多对多:models.ManyToManyField(其他表)
一对一:models.OneToOneField(其他表)
应用场景:
    一对多:当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择)
        例如:创建用户信息时候,需要选择一个用户类型【普通用户】【金牌用户】【铂金用户】
    多对多:在某表中创建一行数据时,有一个可以多选的下拉框。
        例如:创建用户信息,需要为用户指定多个爱好。
    一对一:在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了)
        例如:有个身份证表,有个person表。每个人只能有一张身份证,一张身份证也只能对应一个人,这就是一对一关系。

1.1 一对多关系,即外键
    为什么要用一对多。先来看一个例子。有一个用户信息表,其中有个用户类型字段,存储用户的用户类型。如下:
        class UserInfo(models.Model):
            username = models.CharField(max_length=32)
            age = models.IntegerField()
            user_type = models.CharField(max_length=10)
    不使用外键时用户类型存储在每一行数据中。如使用外键则只需要存储关联表的id即可,能够节省大量的存储空间。同时使用外键有利于维持数据完整性和一致性。
    当然也有缺点,数据库设计变的更复杂了。每次做DELETE 或者UPDATE都必须考虑外键约束。
    
    刚才的例子使用外键的情况:单独定义一个用户类型表:
        class UserType(models.Model):
            caption = models.CharField(max_length=32)

        class UserInfo(models.Model):
            user_type = models.ForeignKey('UserType')
            username = models.CharField(max_length=32)
            age = models.IntegerField()
            
    我们约定:
        正向操作: ForeignKey在UserInfo表里,如果根据UserInfo去操作就是正向操作。
        反向操作: ForeignKey不在UserType里,如果根据UserType去操作就是反向操作。
        
    一对多的关系的增删改查:
        正向操作:
             增
                1)创建对象实例,然后调用save方法:
                    obj = UserInfo(name='li', age=44, user_type_id=2)
                    obj.save()
                2)使用create方法
                    UserInfo.objects.create(name='li', age=44, user_type_id=2)
                3)使用get_or_create方法,可以防止重复
                    UserInfo.objects.get_or_create(name='li', age=55, user_type_id=2)
               4)使用字典。
                    dic = {'name':'zhangsan','age':18,'user_type_id':3}
                    UserInfo.objects.create(**dic)
                5)通过对象添加 
                    usertype = UserType.objects.get(id=1)
                    UserInfo.objects.create(name='li', age=55, user_type=usertype)
                    
                和普通模式一样删除即可。如:
                    UserInfo.objects.filter(id=1).delete()

             改  
                和普通模式一样修改即可。如:
                    UserInfo.objects.filter(id=2).update(user_type_id=4)
                    
             查 
                正向查找所有用户类型为钻石用户的用户,使用双下划线:
                    users = UserInfo.objects.filter(user_type__caption__contains='钻石')
                    正向获取关联表中的属性可以直接使用点.语法,比如获取users查询集中第一个用户的caption:
                    users[0].user_type.caption
                    
        反向操作:
            增 (一般使用正向增即可)
                通过usertype来创建userinfo
                1) 通过userinfo_set的create方法
                    #获取usertype实例
                    ut = UserType.objects.get(id=2)
                    #创建userinfo
                    ut.userinfo_set.create(name='smith',age=33)

             删 
                删除操作可以在定义外键关系的时候,通过on_delete参数来配置删除时做的操作。
                on_delete参数主要有以下几个可选值:
                    models.CASCADE  默认值,表示级联删除,即删除UserType时,相关联的
                                    UserInfo也会被删除。
                    models.PROTECT  保护模式, 阻止级联删除。
                    models.SET_NULL 置空模式   设为null,null=True参数必须具备
                    models.SET_DEFAULT 置默认值 设为默认值,default参数必须具备
                    models.SET()    删除的时候重新动态指向一个实体访问对应元素 ,可传函数
                    models.DO_NOTHING   什么也不做。
                注意: 修改on_delete参数之后需要重新同步数据库,如果使用
                       python manage.py shell进行models操作,需要退出shell重新进入。
            
                 和普通模式一样,不会影响级联表。
                
             查 
                 通过usertype对象来查用户类型为1的用户有哪些
                obj=UserType.objects.get(id=1)
                obj.userinfo_set.all() 

                 可以通过在定义foreignkey时指定related_name来修改默认的userinfo_set,比如指定related_name为info
                    user_type = models.ForeignKey('UserType',related_name='info')
                指定related_name之后,反向查的时候就变成了:
                    obj.info.all()
                获取用户类型为1且用户名为shuaige的用户
                    obj.info.filter(username='shuaige')

                 外键关系中,django自动给usertype加了一个叫做userinfo的属性。使用双下划线,可以通过userinfo提供的信息来查usertype (了解)
                    user_type_obj = UserType.objects.get(userinfo__username='zs')
1.2 多对多关系
        针对多对多关系django会自动创建第三张表。也可以通过through参数指定第三张表。
        用户和组是典型的多对多关系:
            class Group(models.Model):
                name = models.CharField(max_length=20)

                def __str__(self):
                    return self.name
            class User(models.Model):
                name = models.CharField(max_length=64)
                password = models.CharField(max_length=64)
                groups = models.ManyToManyField(Group)

                def __str__(self):
                    return self.name
        操作: 
            增: 
                先分别创建user和group, 再使用add关联
                    u = User(name='aa', password='123')
                    u.save()
                   g = Group(name='g5')
                   g.save()
                通过Manager对象使用add()方法
                    u.groups.add(g)  或  g.user_set.add(u)
                    
             删: 
                和一对多类似,删除user或group会级联删除user_groups表中的关联数据
             改:
                和一对多类似,只修改当前表
             查:
                正向:
                    查询id=2的用户所在的所有组group
                    u = User.objects.get(id=2)
                    u.groups.all()
                反向:
                    查询id=1的组中包含的所有用户
                    g = Group.objects.get(id=1)
                    g.user_set.all()

1.3 一对一关系
    一对一不是数据库的一个连表操作,而是Django独有的一个连表操作。一对一关系相当于是特殊的一对多关系,只是相当于加了unique=True。
    一个人只能有一张身份证,一张身份证对应一个人,是一个典型的一对一关系。
        class IdCard(models.Model):
            idnum = models.IntegerField()
            def __str__(self):
                return str(self.idnum)
        class Person(models.Model):
            idcard = models.OneToOneField(IdCard)
            name = models.CharField(max_length=20)
            def __str__(self):
                return self.name
            
    一对一关系比较简单。两种表互相都有对方。比如:
        >>> lisi = Person.objects.get(id=3)
        >>> lisi.idcard
        <IdCard: 123456>
        >>> ids = IdCard.objects.get(id=3)
        >>> ids.person
        <Person: lisi>
 

4.F和Q

 
Q查询——对对象的复杂查询
F查询——专门取对象中某列值的操作
导入Q,F对象 :
    from django.db.models import Q,F
F:主要作用
    1)和models自身的字段进行对比。比如:
        Student.objects.filter(age__gt=F('age2'))
    2) 对字段进行数学运算。比如:
        Student.objects.filter(age__gt=F('age2') * 2)

Q:
    且操作:
        默认情况下Django的查询只是且操作如下:
         找到用户为zhangsan并且age=18的数据
            UserInfo.objects.filter(username='zhangsan',age='18')
    或操作: 
        如果需要执行或操作 ,就需要使用到Q对象了
        Q对象可以用 & | ~  (与,或,非)去连接
            UserInfo.objects.filter(Q(age__gt=20) & Q(age__lt=50))
             UserInfo.objects.filter(Q(age__gt=20) | Q(age__lt=50))
             UserInfo.objects.filter(~Q(age__lt=50))
        等于: WHERE question LIKE 'Who%' OR question LIKE 'What%'
        如果Q和关键字参数一起使用的话,Q必须放在关键字参数前面:
        Student.objects.get(Q(age__gt=20) | Q(age__lt=50), name__contains='zhang')
        
 

5.models的Manager

django通过models的manager来执行数据库操作。
每个django model至少有一个manager。
可以自定义manager。
自定义manager必须继承自models.Manager
给默认的manager改名:
    class Person(models.Model):
        ...
        people = models.Manager()
        
定制manager
1)增加额外的方法:
    class BookManager(models.Manager):
        def title_count(self, keyword):
            return self.filter(title__icontains=keyword).count()
    class Book(models.Model):
        title = models.CharField(max_length=100)
        authors = models.ManyToManyField(Author)
        publisher = models.ForeignKey(Publisher)
        publication_date = models.DateField()
        num_pages = models.IntegerField(blank=True, null=True)
        objects = BookManager()

        def __str__(self):
            return self.title
2)修改默认manager的查询集
    class DahlBookManager(models.Manager):
        def get_queryset(self):
            return super(DahlBookManager, self).get_queryset().filter(author='Roa')
    class Book(models.Model):
        title = models.CharField(max_length=100)
        author = models.CharField(max_length=50)
        objects = models.Manager() # The default manager.
        dahl_objects = DahlBookManager() # The Dahl-specific manager.
        
3)使用多个manager
    class MaleManager(models.Manager):
        def get_queryset(self):
            return super(MaleManager, self).get_queryset().filter(sex='M')

    class FemaleManager(models.Manager):
        def get_queryset(self):
            return super(FemaleManager, self).get_queryset().filter(sex='F')

    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        last_name = models.CharField(max_length=50)
        sex = models.CharField(max_length=1, 
                               choices=( ('M', 'Male'),  
                                        ('F', 'Female') )
                               )
        people = models.Manager()
        men = MaleManager()
        women = FemaleManager()
        
        
 

Django (五) modeld进阶的更多相关文章

  1. Django入门到进阶-更适合Python小白的系统课程

    Django入门到进阶-更适合Python小白的系统课程 整个课程都看完了,这个课程的分享可以往下看,下面有链接,之前做java开发也做了一些年头,也分享下自己看这个视频的感受,单论单个知识点课程本身 ...

  2. 【python】-- Django ORM(进阶)

    Django ORM(进阶) 上一篇博文简述了Django ORM的单表操作,在本篇博文中主要简述Django ORM的连表操作. 一.一对多:models.ForeignKey() 应用场景:当一张 ...

  3. 实验五 css进阶应用

    实验五 css进阶应用 实验目的: 掌握CSS在列表中的应用,能利用CSS将列表做成精美的导航栏: 掌握CSS在表单元素中的应用: 掌握SPRY菜单的制作方法和CSS代码修改. 实验内容: 1. 制作 ...

  4. Django之Models进阶操作(字段属性)

    字段属性详细介绍 一.字段 AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) - bigint自增列, ...

  5. 框架----Django框架(进阶篇)

    一.Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接数据库,并编写数据访问层代码 业务逻辑层去调用数据访问层 ...

  6. Django的学习进阶(三)————ORM

    django框架是将数据库信息进行了封装,采取了 类——>数据表 对象——>记录 属性——>字段 通过这种一一对应方式完成了orm的基本映射官方文档:https://docs.dja ...

  7. 冰冻三尺非一日之寒--Django框架【进阶篇】

    第十九章  Django进阶 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接数据库,并编写数据访问层代码 业务逻辑层去 ...

  8. Python之路【第十七篇】:Django之【进阶篇】

    Python之路[第十七篇]:Django[进阶篇 ]   Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接 ...

  9. Django 之models进阶操作

    到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接数据库,并编写数据访问层代码 业务逻辑层去调用数据访问层执行数据库操作 ...

随机推荐

  1. 03-树2 List Leaves(25 point(s)) 【Tree】

    03-树2 List Leaves(25 point(s)) Given a tree, you are supposed to list all the leaves in the order of ...

  2. linux下mysql开启二进制日志

    mysql的查询日志,慢查询日志,错误日志,网上的设置方法是正确的.但在二进制日志上设置有问题.正确的设置方法如下, 在/etc/my.cnf文件中[mysqld]下加上: server-id = 1 ...

  3. html5--5-1 了解canvas元素

    html5--5-1 了解canvas元素 学习要点 如何在HTML5文档中添加canvas元素 canvas的属性 了解canvas坐标系 了解script元素 绘制一条直线(准确的说是线段) 什么 ...

  4. python berkeley 操作——尤其提示 需版本匹配

    python berkeley 操作 先到http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/dow ...

  5. Jquery 获取所有对象的第一个子元素

    转自:http://blog.sina.com.cn/s/blog_5fdbd0410100pmnn.html <ul>  <li>John</li>  <l ...

  6. 「LuoguP1220」 关路灯(区间dp

    题目描述 某一村庄在一条路线上安装了n盏路灯,每盏灯的功率有大有小(即同一段时间内消耗的电量有多有少).老张就住在这条路中间某一路灯旁,他有一项工作就是每天早上天亮时一盏一盏地关掉这些路灯. 为了给村 ...

  7. ​MongoDB复制集相关方法使用(五)

    这里我们把复制集中可用的方法都实验一遍,帮助我们更好地来理解复制集.提前说明这些方法的使用是基于Mongodb3.2版本来的,看这篇文章之前需要先看上一篇文章. 介绍一下复制集可用的相关方法 rs.h ...

  8. hibernate VS mybatis

    1: 一般来说,业务逻辑比较简单,集增删改查就可以满足需求,建议使用hibernate,而复杂的业务逻辑,尤其是多表关联查询,建议使用mybatis. 2: hibernate有更好的二级缓存机制,可 ...

  9. 五、怎样修改oracle某个用户的密码

    1.键入命令:sqlplus / as sysdba 2.在sqlplus窗口执行命令: alter user you_username identified by you_password;

  10. Ubuntu无法访问Windows磁盘, 且无提示信息

    现象描述, 双系统Ubuntu和Windows, 进入Ubuntu后无法访问Windows盘内容, 且图标闪烁无任何错误信息提示. 1.安装ntfsfix sudo apt-get install n ...