zoukankan      html  css  js  c++  java
  • Django的Model类

    1、model

    用来和数据交互的(读取和传入数据)

     2、orm

    Object Relational Mapping对象关系映射,python中的model对象和数据库中的表做映射

    3、重要概念

    3.1、类-表对应

    model中的一个类对应数据库中的一个表。实现方式:继承Model类(django.db.models.Model)

    3.2、属性-字段

    类中的属性对应数据库中的字段

    3.2.1、类型

    CharField   字符类型

    IntegerField  数值类型,choise枚举类型数据,元祖包元祖

    type = models.IntegerField(choices=((1,'机构'),(2,'课程'),(3,'讲师')),verbose_name="类别")

    BooleanField   布尔类型

    NullBooleanField  可以为空的布尔值

    AutoField    int自增列,必须填入参数 primary_key=True,auto_create,自动创建,mysql的auto_increment

    FloatField   浮点型

    DecimalField  同Python的Decimal类型,参数:max_digits 最大总位数,decimal_places 小数点后的位数

    TextField   文本类型

    UUIDField   字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证

    # 模型类
    class Order(models.Model):
        no = models.UUIDField(verbose_name='订单编号')
        price = models.DecimalField(verbose_name='订单金额',max_digits=6, decimal_places=2)
        pay_state = models.BooleanField(default=False)
    
    # 创建对象
    import uuid
    Order.objects.create(no=uuid.uuid4(),price=1819.567,pay_state=True)   # price只保留两位小数,会自动四舍五入

    FileField   文件,字符串,路径会保存到数据库,文件上传到指定目录

      参数:upload_to = ""  上传文件的保存路径,storage = None  存储组件,默认django.core.files.storage.FileSystemStorage

    ImageField   图片,路径保存到数据库,文件上传到指定目录

      参数:upload_to = ""      上传文件的保存路径

           storage = None      存储组件,默认django.core.files.storage.FileSystemStorage

         width_field=None,   上传图片的高度保存的数据库字段名(字符串)

         height_field=None   上传图片的宽度保存的数据库字段名(字符串)

    DateField   日期类型,格式:格式:YYYY-MM-DD

      参数:auto_now 每次保存时,自动设置当前字段为当前时间,用于最后一次修改

           auto_now_add  每一次保存时,自动设置为当前时间,用于“创建时间”

      注意:auto_now和auto_now_add及default只能设置一个,不能组合

    DateTimeField   日期时间类型  datetime.datetime,日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]

    TimeField   时间类型, 格式: HH:MM[:ss[.uuuuuu]]

    3.2.2、约束

    max_length   最大长度

    default   默认值

    unique  唯一值

    primary_key  主键

    null  

    blank  是否允许输入为空,即输入空字符串

    db_index  索引

    db_column  指定字段名

    verbose_name 在admin显示字段名称

    choices  一个包含多元素元组的可迭代的对象,用于给字段提供选项

    3.2.3、关系

    ForeignKey  一对多,将字段定义在多端,自动在多端中添加一个外键,如:store = ForeginKey(Store, db_column="外键的列名"),外键字段: store_id

    OneToOneField  一对一,将字段定义在任意一端

    ManyToManyField   多对多,将字段定义在两端

    4、元信息

    在Model的子类中定义Meta来声明表的相关信息

    # 需要定义在类的内部
    class Meta:
        app_label=''   # 应用名
        db_table=''    # 表名
        ordering = []   # 排序字段,字段名前可使用'-'表示倒序
        verbose_name = ''   # admin中所显示的名称
        unique_together= ''  # 来设置的不重复的字段组合

    5、CRUD

    5.1、增

    5.1.1、通过模型类对象管理器插入记录

    语法:模型类名.objects.create(类属性=值)  此方式是直接操作数据库

    stu1 = Student.objects.create(name='Negan',sex='m',score=95.0)

    5.1.2、实例化模型对象插入数据

    car = Car(name="宝马3",price=20.5)
    car.save()
    car = Car()
    car.name="宝马5i"
    car.price=50.5
    car.save()

    通过对象模型进行插入操作是在内存中执行的,也就是说在没有save()之前都是在内存中操作,和数据库没有关系,只有在save()后,才将数据加载到数据库

    5.2、查

    5.2.1过滤器

    filter  选出符合条件的数据,可以包含多个字段,用“,”隔开表示与的关系

    s1 = Student.objects.filter(sex='m',name='Neagn')
    
    # 支持链式调用
    s1 = Student.objects.filter(sex='m').filter(name='Negan')

    exclude  去掉符合条件的

    s1 = Student.objects.filter(sex='m').exclude(socre=72)  # 找出性别为m以及分数不是72的

    5.2.2条件

    语法:属性名__运算符=临界值

    gt  大于  

    Car.objects.filter(price__gt=30)

    lt  小于

    gte  大于等于

    lte   小于等于

    exact   精确内容查找,区分大小写

    iexact    i 代表ignore(忽略),即忽略大小写

    contains   内容包含,相当于模糊查询

    Car.objects.filter(name__contains='')

    startswith    以...开头

    endswith    以..结尾

    istartswith    以...开头,忽略大小写

    endswith   以..结尾,忽略大小写

    icontains   包含xx字符,忽略大小写

    in  包含值项 

    Car.objects.filter(price__in=(30.58,26.65))

    isnull    为null

    isnotnull   非null

    5.2.3、获取对象

    ①集合对象QuerySet(可以使用循环,也可以进行切片操作)

      filter() 返回符合条件的数据

      exclude() 过滤掉符合条件的数据

      all() 获取所有的对象

    ②单个对象

      get() 要求条件对应的数据有且只有一个

      注意:如果没有找到符合条件的对象,会引发 模型类.DoesNotExist异常

         如果找到多个,会引发  模型类.MultiObjectsReturned 异常

      last() 返回查询集中的最后一个对象

      first() 返回查询集中第一个对象

    ③其他方法

      count() 返回查询集中对象的个数

      exists() 判断查询集中是否有数据,如果有返回True,反之返回False

      values() 一条数据就是一个字典,返回一个列表

        使用values()可以查询某个(些)字段

        模型类名.objects.values("属性名")或模型类名.objects.values("属性名1","属性名2",...),返回QuerySet容器对象,其中的元素以字典格式表示

        模型类名.objects.values_list("属性名")或模型类名.objects.values_list("属性名1","属性名2",...),返回QuerySet容器对象,其中的元素以元祖格式表示

      order_by() 排序

    5.2.3、聚合函数aggregate()

    帮助我们去计算一些属性的值

    需要先导入相关的包

    from django.db.models import Count,Min,Sum,Max,Avg
    avg_score = Student.objects.all().aggregate(Avg("score")) # 返回一个字典  {'score__avg': 69.42857142857143}
    
    # 自定义结果字典的key
    avg_score =Student.objects.all().aggregate(avgscore=Avg("score"))
    
    >> {'avgscore': 69.42857142857143}

    # 也可以写成下面的形式,默认计算的是所有的结果集
    avg_score =Student.objects.aggregate(avgscore=Avg("score"))

    5.2.4、分组查询annotate()  

    students = Student.objects.values('sex').annotate(Avg('score'))

    5.2.5、F对象

    可以将自己的属性作为条件值

    from django.db.models import  F
    
    Store.objects.filter(id=F('years'))  #查询Store的id和years两个属性相同的记录
    
    Company.objects.filter(boy__lt=F("girl"))  # 查询男生比女生人数少的公司

    并且支持算术运算

    grades = Grade.objects.filter(ggirlnum__gt=F('gboynum') +10 )
    
    
    Store.objects.filter(id=1).update(years=F('years')+5)

    5.2.6、Q对象

    查询条件的封装,过滤器方法中的关键参数,常用语组合条件

    from django.db.models import Q
    
    Student.objects.filter(Q(sage__lt=25))  # 查询年龄小于25

    可以进行逻辑运算:

      & 与

      | 或

      ~ 非

    Store.objects.filter(Q(years=1) | Q(years=2))
    
    Store.objects.filter(~Q(years=1)))
    
    Store.objects.filter(Q(years__gt=1) & Q(years__lt=3))

    5.3、原生sql查询

    5.3.1、extra()方法

    queryset.extra(参数)

    students = Student.objects.filter(name__contains='').extra(where=['score>55','age>50'])

    5.3.2、raw()方法

    对象管理器.raw(原生sql)  注意:查询字段必须包含主键

    books = Book.objects.raw("select id,name,price from books")

    5.3.3、execute()

    类似于pymysql的用法,灵活度很高,并且完全不依赖Model类

    from django.db import connection
    cursor = connection.cursor()
    cursor.execute("select name,price from books")
    
    books = cursor.fetchall() # 包含结果集的元组

    5.4、删

    delete() 基于查询, 先查取出来,再执行删除 

    s = Student.objects.get(id=3)
    s.delete()

    5.5、改

    save() 基于查询,先查询出来,再去修改,存储

    也可以使用 filter(xxx=). update(xxx=)

    6、模型对应关系

    6.1、显性对象

    开发者手动创建的对象,在模型类中,开发者声明的属性字段

    6.2、隐性对象

    系统为我们自动补充创建的对象

    objects是一个Manager类型的对象,作用域数据库进行交,当模型类没有指定管理器的时候,Django会自动为我们创建模型管理器,如果手动指定,则系统不会在为我们生成这个对象。

    如下创建一个model类,迁移后可以正常查询。

    
    
    class Animal(models.Model):
    name = models.CharField(max_length=10)
    is_delete = models.BooleanField(default=False) # 逻辑删除

    class Meta:
    db_table = 'animal'

    但是如果手动指定一个管理器,则会抛出异常。

    class Animal(models.Model):
    name = models.CharField(max_length=10)
    is_delete = models.BooleanField(default=False)
    m = models.Manager() # 指定管理器

    class Meta:
    db_table = 'animal'
    >>> from myapp.models import *
    >>> a = Animal.objects.all()
    Traceback (most recent call last):
      File "<console>", line 1, in <module>
    AttributeError: type object 'Animal' has no attribute 'objects'

    这时候需要用我们自己定义的管理器进行查询,也就是我们定义的m

    >>> a = Animal.m.all()
    >>> a
    <QuerySet [<Animal: Animal object (1)>, <Animal: Animal object (2)>, <Animal: Animal object (3)>, <Animal: Animal object (4)>
    ]>

     我们需要取is_delete=False的数据,一般情况下都是filter(is_delete=False)这种写法,但是这种写法重复率太高,那么能不能封装一个方法?

    只需要写一个我们自己的管理器类,继承models.Manager,重写get_queryset()方法。

    class AnimalManager(models.Manager):
        def get_queryset(self):
            return super().get_queryset().filter(is_delete=False)
    
    
    class Animal(models.Model):
        name = models.CharField(max_length=10)
        is_delete = models.BooleanField(default=False)
        objects = AnimalManager()
    class Meta: db_table = 'animal'
    >>> a = Animal.objects.all()
    >>> a
    <QuerySet [<Animal: Animal object (1)>, <Animal: Animal object (4)>]>

    6.3、一对一

    6.3.1、实现方式

    在负责维护关系的“一”方添加OneToOneField型的类属性

    主表:重要的表

    从表:维护关系的表

    from django.db import models
    
    class Person(models.Model):
        name = models.CharField(max_length=20)
        age = models.IntegerField()
        sex = models.CharField(max_length=10)
    
    class Card(models.Model):
        cardno = models.CharField(max_length=20,unique=True)   # 卡号类属性
        color = models.CharField(max_length=10)
        person = models.OneToOneField(Person,on_delete=models.CASCADE)  # 使用OneToOneField进行“一对一”关联

    6.3.2、对象间的关联

    方式一:通过主动一方模型类属性,关联另一方对象

    #创建人对象:
    per = Person(name='张三',age=20,sex='')
    per.save()
    
    #通过Card类的person属性关联
    card = Card(cardno='zs123456',color='绿卡',person=per)
    card.save()

    方式二:通过对应表的唯一外键字段关联

    per1 = Person(name='李四',age=22,sex='')
    per1.save()
    
    card1 = Card.objects.create(cardno='ls123456',color='黄色',person_id=per1.id)

    6.3.3、查询

    从维护关系的"一"方查询:使用模型类中维护关系的那个类属性

    #查询3号卡关联的人
    card = Card.objects.get(id=3)
    per = card.person  # 使用关联的类属性查询

    从不维护关系的"一"方查询:使用对方模型类名的小写

    查询1号人的卡:
    per1 = Person.objects.get(id=1)
    card1 = per1.card  # 使用对方模型类名的小写

    6.4、一对多

    6.4.1、实现方式

    通过在"多"方模型类中添加外键属性ForeignKey

    class School(models.Model):   # "一"方模型
        name = models.CharField(max_length=30)
        address = models.CharField(max_length=30)
        history = models.TextField(null=True)
    
    class Student(models.Model):  # "多"方模型
        name = models.CharField(max_length=10)
        age = models.IntegerField()
        score = models.FloatField()
        sex = models.CharField(max_length=10)
        school = models.ForeignKey(School,on_delete=models.CASCADE)

    6.4.2、对象间的关联

     方式一:通过"多"方模型的外键类属性关联"一"方模型的实例化对象

    #添加学校对象(“一”方模型对象)
    school1 = School.objects.create(name='清华大学',address='北京中关村')
    
    #school2 = School.objects.create(name='北京大学',address='北京',history='北京大学是一所知名大学')
    
    school3 = School.objects.create(name='西安交通大学',address='西安',history='交大很好')
    
    #通过外键类属性关联:
    stu1 = Student.objects.create(name='张三',age=20,score=93.5,sex='',school=school1)

    方式二:通过“多”方对应表的外键关联"一"方

    通过“多”方对应表的外键关联
    eg:两个学生都上的是3号学校
    
    stu3 = Student.objects.create(name='郭靖',age=23,score=80,sex='',school_id=3)
    
    stu4 = Student.objects.create(name='黄蓉',age=21,score=85,sex='',school_id=3)

    6.4.3、查询

    从"一"查"多": 一方的实例化对象.多方模型类名小写_set.all()

    # 查询1号学校所有的学生:
    school = School.objects.get(id=1)
    students = school.student_set.all()

    从"多"查"一",通过“多”方设置的关联类属性查询

    #查询6号学生对应的学校:
    student = Student.objects.get(id=6)
    school = student.school

    6.5、多对多

    6.5.1、实现方式

    在某个"多"方使用ManyToManyField,关联另一个"多"方和第三方模型维护关系

    使用外键实现,原表是没有任何变化的,是多出一张专门用来维护关系的表,关系表中通过两个外键实现对两张表的关联

    # 系统会自动生成第三方表
    from django.db import models
    
    class Member(models.Model):   # 成员模型
        name = models.CharField(max_length=20)
        age = models.IntegerField()
        sex = models.CharField(max_length=10)
    
        def __str__(self):
            return self.name
    
    class Community(models.Model):  # 社团模型
        name = models.CharField(max_length=20)
        buildtime = models.DateField()
        members = models.ManyToManyField(Member)
    
        def __str__(self):
            return self.name
    # 可以指定生成第三方表
    from django.db import models
    
    class Member(models.Model):   # 成员模型
        name = models.CharField(max_length=20)
        age = models.IntegerField()
        sex = models.CharField(max_length=10)
    
        def __str__(self):
            return self.name
    
    class Community(models.Model):  # 社团模型
        name = models.CharField(max_length=20)
        buildtime = models.DateField()
        members = models.ManyToManyField(Member,through="Relation")
    
        def __str__(self):
            return self.name
    
    class Relation(models.Model):
        member = models.ForeignKey(Member,on_delete=models.CASCADE)
        community = models.ForeignKey(Community,on_delete=models.CASCADE)
        join_reason = models.CharField(max_length=100)

    6.5.2、对象间的关联

    ①系统自动生成第三方表关联数据

    # 创建Member对象:
    m1 = Member.objects.create(name='马小跳',age=20,sex='')
    m2 = Member.objects.create(name='李丽丽',age=25,sex='')
    m3 = Member.objects.create(name='黄大牛',age=35,sex='')
    
    # 创建Community对象:
    c1 = Community.objects.create(name='天涯吉他社',buildtime=date(2016,6,6))
    
    c2 = Community.objects.create(name='读书会',buildtime=date(2017,10,1))
    c3 = Community.objects.create(name='瑜伽协会',buildtime=date(2008,9,3))
    
    # 不维护关系一方属性.维护关系一方类名小写_set.add(维护关系一方的对象)
    
    m1.community_set.add(c1)  # 马小跳加入天涯吉他社
    m1.community_set.add(c2)   # 马小跳加入读书会

    ②通过第三方模型对象维护

    #创建Member对象:
    member1 = Member.objects.create(name='马小跳',age=20,sex='')
    member2 = Member.objects.create(name='李丽丽',age=25,sex='')
    member3 = Member.objects.create(name='黄大牛',age=35,sex='')
    
    
    #创建Community对象:
    community1 = Community.objects.create(name='天涯吉他社',buildtime=date(2016,6,6))
    community2 = Community.objects.create(name='读书会',buildtime=date(2017,10,1))
    community3 = Community.objects.create(name='瑜伽协会',buildtime=date(2008,9,3))
    
    # 创建Relation关系对象,通过实例化对象关联:
    r1 = Relation.objects.create(member=member2,community=community1,join_reason='好玩')
    
    # 通过外键值关联:
    r2 = Relation.objects.create(member_id=member3.id,community_id=community1.id,join_reason='交朋友')

    6.5.3、查询

    ①从主动维护关系的"多"方查询:实例化对象.通过关联的类属性.all()

    #查询3号社团所有的成员:
    
    #方式一:借助关联的类属性直接查询
    
    all_members = community.members.all()
    for m in all_members:
         print(m)
    
    
    #方式二:借助中间模型查询:
    community = Community.objects.get(id=3)
    relations = Relation.objects.filter(community=community)
    
     for r in relations:
          print(r.member)

    ②从不负责维护关系的"多"方查询:实例化对象.对方模型类名小写_set.all()

    查询1号成员参加的社团:
    member1 = Member.objects.get(id=1)
    all_community = member1.community_set.all()
    for c in all_community:
         print(c)

    6.6、模型外键自关联

    场景:在需要引用自身模型的时候

    6.6.1、"一对多"自引用

    models.ForeignKey('self',on_delete=models.CASCADE,null=True)

    from django.db import models
    
    class Emp(models.Model):
        name = models.CharField(max_length=20)
        age = models.IntegerField()
        sex = models.CharField(max_length=10)
        salary = models.FloatField()
        manager = models.ForeignKey('self',on_delete=models.CASCADE,null=True)   # 外键自引用
    
    
    创建最高领导boss和其他员工:
    boss = Emp.objects.create(name='马云',age=55,sex='',salary=3000.5)
    
    emp1 = Emp.objects.create(name='马晓云',age=25,sex='',salary=2000,manager=boss)
    emp2 = Emp.objects.create(name='张勇',age=58,sex='',salary=6000,manager=boss)
    emp3 = Emp.objects.create(name='张三',age=58,sex='',salary=3000,manager=emp2)
    emp4 = Emp.objects.create(name='张丽',age=28,sex='',salary=3000,manager=emp3)
    emp5 = Emp.objects.create(name='张小勇',age=22,sex='',salary=3000,manager=emp2)
    
    查询id为3的员工的直接下属与直属上司:
    emp = Emp.objects.get(id=3)
    workers = emp.emp_set.all()  # 直属下属
    leader = emp.manager
    
    级联删除所有员工:
    boss.delete()

    6.6.2、“一对一”自引用

    models.OneToOneField('self',on_delete=models.CASCADE,null=True)

    from django.db import models
    
    class Spy(models.Model):
        name = models.CharField(max_length=20)
        age = models.IntegerField()
        sex = models.CharField(max_length=10)
        manager = models.OneToOneField('self',on_delete=models.CASCADE,null=True)
    
        class Meta:
            db_table = 'spies'
    
    创建Spy对象boss,并创建其他对象
    boss = Spy.objects.create(name='戴笠',age=45,sex='')
    
    spy1 = Spy.objects.create(name='毛人凤',age=30,sex='',manager=boss)
    
    spy2 = Spy.objects.create(name='张三',age=25,sex='',manager=spy1)
    
    查询boss的直属下属的名字:
    boss.spy.name

    6.7、数据删除 on_delete

    ①、models.CASECADE

     主表删除,从表自动删除(级联数据)

    从表数据删除,主表不受影响

    ②、models.PROTECT  

    开发中为了防止误操作,我们通常会设置为此模式,

    主表如果存在级联数据,删除动作受保护,不能成功

    主表不存在级联数据,可以删除成功

    ③、SET

      SET_NULL,主表删除时,从表的外键列值为null,注:必须设置null=True

      SET_DEFAULT   存在默认值

      SET()   指定值

    6.8、模型的面向对象

    Django中模型支持继承

    默认继承是会将通用字段放到父表中,特定字段放在自己的表中,中间使用外键连接

    关系型数据库关系越复杂,效率越低,查询越慢

    父类表中也会存储过多的数据

    使用元信息来解决这个问题

    使模型抽象化,抽象的模型就不会在数据库中产生映射了.子模型映射出来的表直接包含父模型的字段

    class Animal(models.Model):
        a_name = models.CharField(max_length=16)
    
        class Meta:
            abstract = True
    
    
    class Cat(Animal):
        c_eat = models.CharField(max_length=32)

    6.9补充

    在企业开发中,model--->sql,我们可以使用django_migrations

    同样的sql--->model,在Django中也同样支持

    python manage.py inspectdb

    可以直接根据表生成模型,元信息中包含一个属性 manage=False

    如果自己的模型不想被迁移系统管理,也可以使用 manage=False进行声明

      

  • 相关阅读:
    Python机器学习(五十一)SciPy 介绍
    Python机器学习(五十)NumPy 线性代数
    Python机器学习(四十九)NumPy 矩阵库函数
    Python机器学习(四十八)NumPy 副本和视图
    Python机器学习(四十七)NumPy 排序、查找、计数
    Python机器学习(四十六)NumPy 统计函数
    Python机器学习(四十五)NumPy 数学函数
    Python机器学习(四十四)NumPy 字符串函数
    Python机器学习(四十三)NumPy 位运算
    Python机器学习(四十二)NumPy 数组迭代
  • 原文地址:https://www.cnblogs.com/huiyichanmian/p/12147131.html
Copyright © 2011-2022 走看看