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进行声明

  

原文地址:https://www.cnblogs.com/huiyichanmian/p/12147131.html