Django模型M

模型M

一.Django ORM

  1. 创建项目 django-admin stareproject 项目名
  2. 创建应用 python manae.py startapp 应用名
  3. 连接数据 mysql -u root -p
  4. 创建数据库表 create databases 数据库名 charser=UTF8

二.Django配置使用mysql数据库

settings.py 配置下面的数据

1
2
3
4
5
6
7
8
9
10
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', #指定连接mysql数据库
'NAME':'bj18', #数据库名字//数据库需要手动创建
'USER':'root', #连接mysql的用户名
'PASSWORD':'mysql', #用户对应的密码
'HOST':'localhost', #指定mysql数据库只当数据库所在IP
'PORT':3306, #用户端口号 默认3306
}
}

在settings.py 同级的 __init__.py 下面配置 (看需求配置!!)

1
2
import pymysql
pymysql.install_as_MySQLdb()

三.重定向

四.字段属性和选项

###模型类属性命名限制

  1. 不能是python的保留关键字。

  2. 不允许使用连续的下划线,这是有Django的查询方式决定的。

  3. 定义属性时需要制定字段类型,通过字段类型的参数指定选项,语法如下:

    #####属性名 = models.字段类型选项

字段类型:

使用时候需要引入django.db.models 包

类型 描述 备注
AutoField 自动增长的IntegerField,通常不用指定,不指定时Django会自动创建属性名为id的自动增长属性
BooleanField 布尔字段,值为True或False type(True) ==bool类型
NullBooleanField 支持Null、True、False三种值
CharField(max_length=最大长度) 字符串。参数max_length表示最大字符个数
TextField 大文本字段,一般超过4000个字符使用
IntegerField 整数
DecimalField(
max_digits=None,
decimal_places=None)
十进制浮点数。参数manx_digits表示总位。参数decimal_places表示小数位。
DeteField:(
[auto_now=False,
auto_now_add=False])
日期
一:参数auto_now表示每次保存对象时,自动设置该子弹为当前时间“”最后一次修改”的时间戳,它总是使用当前日期,默认为false。
二:参数auto_now_add表示当对象第一次被创建是自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false.
三:参数 auto_now_add 和auto_now 是相互排斥的,组合将会发生错误。
TimeField 时间,参数同DateField
DateTimeField 日期时间,参数同DateField
FileField 上传文件字段。
ImageField 继承与FileField,对上传的内容进行校验,确保是有效的图片。

选项:

通过选项实现对字符串字段的约束,选项如下:

选项名称 描述
defaule 默认值。设置默认值。
primary_key 若为Ture,则该字段会成为模型的主键字段,默认值为False,一般作为Autofield的选项使用。
unique 如果为True,这个字段在表中必须是唯一值,默认值是False.
db_index 若值为True,则在表中会为此字段创建索引,默认值是False.
db_column 字段的名称。如果未指定,则使用属性的名称。
null 如果为True,表示允许为空,默认值是False
blank 如果为True,则该字段允许为空白,默认为False.

对比:null是数据库范畴的概念,blank是后台管理页面表单验证范畴的。

经验:

当修改模型类之后如果添加的选项不影响表结构,则不需要重新做迁移,商品选项中default和blank不影响表结构。

五.查询

###1.Linux修改Mysql的日志文件:

让其产生mysql.log,及是mysql的日志文件,里面记录的对mysql数据库的操作记录。

  1. 使用下面的命令打开mysql的配置文件,去除68,69行的注释,然后保存。

    1
    sudu vi /etc/mysql/mysql.comf.d/mysqld.cnf
  2. 重启mysql服务,就会产生mysql的日志文件。

    1
    sudu service mysql restart
  3. 打开mysql日志文件。

    1
    /var/log/mysql/mysql.log 是mysql日志文件所在位置。

    使用下面命令可以实现查看mysql的日志文件:

    1
    sudo tail -f /var/log/mysql/mysql.log

2.查询函数:

通过模型类:objects 属性可以调用如下函数,实现对模型类对应的数据表查询。

函数名 功能 返回值 说明
get 返回表中满足条件的一条且只能有一条数据。 返回值是一个模型类对象 参数中写查询条件。
1.如果查到多个数据,则抛出异常 MultipleObjectsReturned.
2.查询不到数据,则抛出异常:DoesNotExist.
all 返回模型类对应表格中的所有数据 返回值是ouerySet类型。 查询集
filter 返回满足条件的数据。 返回值是OuerySer类型。 参数写查询条件
exclude 返回不满足条件的数据。 返回值是ouerySet类型 参数写查询条件
order_by 对查询结果进行排序 返回值是OuerySet类型 参数中写根据那个字段进行排序

get

查询一条信息

all

查询所有信息

filter

条件格式:

模型类属性名__条件名 = 值 (双下划线)

1.判等 exact

查询编号为1的图书。

bookInfo.objects.get(id=1)

bookInfo.objects.get(id__exact=1)

2.模糊查询
  • 包含 contains

    查询包含传的图书:

    bookInfo.objects.filter(dtitle__contains=’传’)

  • 以什么结尾 endswith

    bookInfo.objects.filter(dtitle__endswith=’xxx’)

  • 以什么开头 startswith

    bookInfo.objects.filter(dtitle__ startswith=’xxx’)

#####3.空查询 isnull

​ bookInfo.objects.filter(btitle__isnull=False) 查询不为空的值

4.范围查询 in
5.比较查询
gt 大于
lt 小于
gte 大于等于
lte 小于等于
6.日期查询
7.exclude 返回不满足条件的值。

​ 与 filter 相反 exclude 返回不满足条件的值。

8.order_by 方法示例

​ 作用:进行查询结果进行排序。

​ 正序:字段名 .objects .all().order_by(‘字段’) 可以根据多个字段进行排序 升序从小到大

​ 倒序:字段名 .objects .all().order_by(‘-字段’) 可以根据多个字段进行排序 降序从大到小 降序在字段前面加上 负号即可

​ 查询条件加排序:字段名.objects.filter(字段__判断条件=‘判断内容’).order_by(‘排序字段’) 默认升序,加上 负号 降序。

总结:

只有get 返回一个模型的对象,其他查询条件返回的都是 查询集的对象。

多条件查询:

filter,exclude 可以多个条件查询。

条件之间是且的关系,

六.F对象

作用:用于类属性之间的比较。

解释F:之前我们的查询都是对一个值进行比较,而F对象适用于跟一个 属性之间进行比较。

使用之前需要导入:

1
from django.db.models import F

例:查询阅读量大于评论量图书的信息。

1
2
使用F把表内字段 包起来就行了。
BookInfo.objects.filter(bread__gt = F( "bcomment" ))

例:查询图书阅读量大于2倍评论量的图书信息。

1
2
直接在后面写 * 2 就OK
BookInfo.objects.filter(bread__gt = F( "bcomment" )*2)

七:Q对象、

作用:用于查询是条件之间的逻辑。and or not ,可以对Q对象进行 &|~ 操作。

使用之前需要先导入:

1
from django.db.models import Q
Q 所查询的对象需要被Q()包含
| 逻辑或
& 和逻辑与
~ 逻辑非

例:查询id大于3且阅读量大于30的图书信息。

1
2
3
4
5
普通方法  两个条件是逻辑与的关系。
BookInfo.objects.filter( id__gt=3 , bread__gt=30 )

Q对象方法 要被查询的字段需要被Q()包含 &代表逻辑与
BookInfo.objects.filter( Q(id__gt=3) & Q(bread__gt=30) )

例:查询id大于3或者阅读量大于30的图书信息。

1
2
| 是逻辑或  用它连接Q的条件。
BookInfo.objects.filter( Q(id__gt=3) | Q(bread__gt=30) )

例:查询id不等于3的图书信息。

1
2
~ 不等于的意思,
BookInfo.objects.filter(~ Q(id=3) )

八.聚合函数

作用:对查询结果进行聚合操作。 导入的时候首字母为大写。

名称 作用
sum 总计
count 统计数
avg 平均值
max 最大值
min 最小值

aggregate:调用这个函数来使用聚合。返回一个值是字典。

使用之前需先导入聚合类: 用哪个导入那个

1
from django.db.models import Sum,Count,Max,Min,Avg

###aggregate函数

例:查询所有图书的数目。

1
2
必须制定某一个字段不能使用 * 
BookInfo.objects.all() . aggregate( Count ('id') )

例:查询所有图书阅读量的综合。

1
BookInfo.objects . aggregate( Sum ('bread') )

count 函数

返回值是一个数字。

作用:统计满足条件数据的数目。

例:统计所有图书的数目。

1
2
3
4
返回一个数字 返回所有读书的数量
BookInfo.objects.all().count()
针对查询所有all可以省略。
BookInfo.objects.count()

例:统计id大于3的所有图书数目。

1
2
对数据进行筛选之后,在使用count函数。
BookInfo.objects.filter(id__gr=3).count()

查询相关函数!!

  • get:返回一个且只能有一条数据,返回值是一个对象,参数可以写查询条件。

  • all:返回模型类对应表的所有数据,返回值是QuerySet.

  • filter:返回满足套件的数据,返回值是QuerySet,参数可以写查询条件。

  • exclude:返回不满足条件的数据,返回值是QuerySer,参数可以写查询条件。

  • order_by:对查询结果进行排序返回值是QuerySet,参数中写排序的字段。

1
from django.db.models import F,Q,Count,Max,Min
  • F对象:用于类属性之间进行比较。
  • Q对象:用于条件之间的逻辑关系。
  • aggregate:进行聚合操作,返回值是一个字典,进行聚合的时候,需要先导入聚合类。
  • count:返回结果集中数据的目的,返回值是一个数字。

注意:

​ 对一个QuerySet实例对象,可以据需调用上面的所有函数。

注意:

  1. 通过模型类实现关联查询时,要查那个表中的数据,就需要通过那个类来查。
  2. 写关联查询条件的时候,如果类中没有关系属性,条件需要对应类的名,如果类中有关系属性,直接写关系属性。

九.查询集

all 、 filter 、 exclude 、 order_by 调用这些函数会产生查询集,QuerySet类对象可以继续调用上限所有函数。

  1. 惰性查询:只有在实际使用查询集中的数据的时候才会发生对数据的真正查询。
  2. 缓存:当使用的是统计一个查询集的时候,第一次的时候就会发生实际数据库的查询,然后把结果缓存起来,之后在使用这个查询集的时候,使用的是缓存的结果。

限制查询集:

可以对一个查询集进行去下表或者切片操作来限制查询集的结果。

对一个查询集进行切片操作会产生一个新的查询集,下表不允许为负数。

取出查询集第一条数据的两种方式:

方式 说明
b[0] 如果 b[0] 不存在,就会抛出一个 IndexError异常。
b[0:1].get() 如果 b[0:1].get() 不存在,就会抛出DoesNotExist异常。

exists:来判断一个查询集中是否有数据。 True False

十.模型类关系

  • 一对多关系
    • 列:图书类 —– 英雄类
    • models.ForeignKey() 定义在多的类中。
  • 多对多关系
    • 列:新闻类 —- 新闻类型类 体育信息 国际新闻
    • models.ManyToManyField() 定义在那个类中都行。
  • 一对一关系。
    • 列:员工基本信息类 —- 员工详细信息类 。 员工工号 。 员工被删除员工详细信息类还在,但是员工号不消失
    • models.OneToOneField 定义在那个类都行。

##十一.关联查询

###一对多:

一对多的关系,例如员工跟部门。一个部门有多个员工。那么在django怎么建立这种表关系呢?

其实就是利用外键,在多的一方,字段指定外键即可。例如员工和部门,员工是多,所以在员工表直接部门即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Department(models.Model):         //建立部门表 继承Model
name = models.CharField(max_length=20) //部门名称 字符20
create_data = models.DateField(auto_now_add=True) //部门创建时间
is_delete = models.BooleanField(default=False)

class Meta:
db_table = "department" //别名


class Employee(models.Model): //建立员工表 继承Model
name = models.CharField(max_length=20) //名字
age = models.IntegerField() //年龄
gender = models.IntegerField(default=0) //性别
# decimal_place = 2表示两位小数,max_digits表示8个数字,包括小数的两位
salary = models.DecimalField(max_digits=8,decimal_places=2) //工资 使用精度浮点
# null=True 表示可以为空,blank=True表示django后台管理输入这个字段可以为空
comment = models.CharField(max_length=300,null=True,blank=True) //评论
hire_data = models.DateField(auto_now_add=True) //创建时间
department = models.ForeignKey("Department") //所在部门 一对多关系

class Meta:
db_table = "employee" //别名
  • 在设置外键时,需要通过on_delete 选项指明主表删除数据时,对于外键引用数据表如何处理,在Django.db.models 中包含了可选常量。

    关联属性on_delete 选项的取值

    • models.CASCADE 此为默认值,级联删除,会删除关联数据

      1
      department = models.ForeignKey('Department',on_delete=models.CASCADE)
    • models.PROTECT 只要存在关联数据就不能删除

      1
      department = models.ForeignKey('Department', on_delete=models.PROTECT)
    • models.SET_NULL 删除数据后关联字段设置为NULL,仅在该字段允许为null时可用(null=True

  • 如果关联的字段不在该应用文件夹的model.py中,那么要写成这样
    1
    department = models.ForeignKey("(应用文件夹名).Department")

    还有一个需要特别注意:

    department = models.ForeignKey(“Department”,related_name=’employee’)时,通过部门查找员工的是用employee。如果不设置的话,是用默认的employee_set(类名的小写+_set)

    一对多的查询

    一个员工所属的部门(查出来的是对象):

    a = Employee.objects.get(id=1)

    b = a.department

    一个部门的全部员工(查出来的是对象):

    a = Department.objects.get(id=1)

    b = a.employee_set.all()

多对多

多对多的关系,例如学生与社团。一个学生可以进多个社团,一个社团可以有多个学生。那么在django怎么建立这种表关系呢?

django建立多对多关系有两种方法。

方法一

1
2
3
4
5
6
7
class Student(models.Model):          //学生表
name= models.CharField(max_length=16) //姓名
birthday=models.DateField() //生日

class Club(models.Model): //班级
name= models.CharField(max_length=16) //名称
members = models.ManyToManyField("Student") //多对多关联

只需要在任意一方加上类似第6行的ManyToManyField就可以了。Django会自动为多对多关联关系创建一张表,用于两张表的联系。

那么查询呢?

1.一个社团的全部成员(查出来的是对象)

1
2
3
c = Club.objects.get(id=1)

c.members.all()

2.一个成员的全部社团(查出来的是对象)

1
2
3
s = Student.objects.filter(id=1)

s.club_set.all() # 类名的小写+_set

方法二

手动创建一张表关联联系。

1
2
3
4
5
6
7
8
9
10
class Student(models.Model):
name= models.CharField(max_length=16)
birthday=models.DateField()

class Club(models.Model):
name= models.CharField(max_length=16)

class Membership(models.Model):
student = models.ForeignKey("Student")
club = models.ForeignKey("Club")

一个学生加入的全部社团:

1
2
3
4
5
6
a = Student.objects.get(id=1)

b = a.membership_set.all() # 查出来的是对象

for i in b:
print(i.club.name)

一个社团的全部学生:

1
2
3
4
5
6
7
a = Club.objects.get(id=1)

b = a.membership_set.all() # 查出来的是对象

for i in b:

print(i.student.name)

在一对多关系中,一对应的类我们把它叫做一类,多对应的关系我们叫多类,我们把多类中定义的建立关联的类属性叫做关系属性。

十二.插入、更新和删除

调用一个模型类的对象save 方法的时候就可以实现对模型类对象数据表的插入和更新。

调用一个模型类对象的delete方法的时候就可以实现对模型类对应数据表的删除。

十三.自关联

自关联是一个特殊的一对多关系。

自关联模型,就是表中的某一列,关联了这个表中的另外一列。最典型的自关联模型就是地区表。省、市、县都在一张表里面。省的pid为null,市的pid为省的id,县的pid为市的id。

1
2
3
4
5
6
7
class Area(models.Model):    
name = models.CharField(max_length=20, verbose_name='名称')
# 自关联(特殊的一对多): 生成的字段名 parent_id
parent = models.ForeignKey('self', verbose_name='上级行政区划')
class Meta:
db_table = 'tb_areas'
verbose_name = '行政区划'

查询方法:

如果知道一个市,叫a市,想查他属于什么省。

1
2
3
4
5
a = Area.objects.get(id=1)

# b就是a市的省份的对象

b = a.parent

如果知道一个省,叫a省,想查他有什么市。

1
2
3
4
5
a = Area.object.get(id=1)

# b就是a省的全部市的对象

b = a.area_set.all() #类名小写+'_set'

十四.管理器

BookInfo.objects.all() —-> objects 是什么东西呢?

答:objects 是Django 帮我自动生成的管理器对象,通过这个管理器可以实现对数据的查询。

objects 是 models.Manger 类的一个对象,自定义管理器之后Django不在帮我们生成默认的 objects 管理器。

  1. 自定义管理器类,这个类继承models.manger类。
  2. 再在集体的模型类李定义一个自定义管理器的对象。

自定义管理器的应用场景:

  1. 改变查询的结果集。

    比如调用BookInfo.books.all() 返回的是没有删除的图书数据。

    下面是一个自定义模型管理器:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class BookInfoManager(models.Manager):  //自定义方法使用manager
    '''图书模型管理器'''
    # 1. 改变查询结果集。
    def all(self):
    #1.调用父类的all,获取所有数据。
    books = super().all() #返回QuerSet对象。
    #2.对数据进行过滤。
    books = books.filter(isDelete = False) //写过滤条件
    #3.返回books
    return books
  1. 添加额外方法。

    管理器类定义一个方法帮我们擦欧总模型类对应的数据表。

    使用 self.model() 就可以创建一个跟自定义管理器对应的模型类对象。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class BookInfo(models.Model):
    name = Model.CharField(max_length=20)
    bpub_date = Model.
    """在表类里定义添加方法"""

    @classmethod
    def create_book(cls,name): //传一个形参
    #1.创建一个图书对象。
    obj = cls()
    obj.name = name
    #2.保存数据库。
    obj.save()
    #3.返回 obj
    return obj

    这种方法定义在模型类里,模型类的内容就会很多,这种方法一般我们通常定义在模型管理器里。

    封装函数:操作模型类对应的数据表(增删改查)都可以写在里面。

    模型管理类与模型类之间的关系

    模型管理类与模型类的关系

十五.元选项

Django默认生成的表名:

​ 应用名小写_模型类名小写

元选项:

​ 需要在模型类中定义一个元类Meta,在里面定义一个雷属性 db_table 就可以只当表名称。

1
2
class Meta:
db_table = 'bookinfo' //指定模型类对应的表名

指定之后需要从新做迁移。

模型元选项

Options.abstract:
如果 abstract = True, 就表示模型是 抽象基类 (abstract base class).

Options.db_table:
该模型所用的数据表的名称:
db_table = ‘music_album’

Options.db_tablespace:
当前模型所使用的数据库表空间 的名字。
默认值是项目设置中的DEFAULT_TABLESPACE,如果它存在的话。
如果后端并不支持表空间,这个选项可以忽略。

get_latest_by
Options.get_latest_by
模型中某个可排序的字段的名称,比如DateField、DateTimeField或者IntegerField。
它指定了Manager的latest()和earliest()中使用的默认字段。

Options.managed
默认为True,意思是Django在migrate命令中创建合适的数据表,并且会在 flush 管理命令中移除它们。
换句话说,Django会管理这些数据表的生命周期。
如果是False,Django 就不会为当前模型创建和删除数据表。

Options.order_with_respect_to
按照给定的字段把这个对象标记为”可排序的“。这一属性通常用到关联对象上面,使它在父对象中有序。
相关联的对象也有两个方法, get_next_in_order() 和get_previous_in_order(),用于按照合适的顺序访问它们。

Options.ordering
对象默认的顺序,获取一个对象的列表时使用:
ordering = [‘-order_date’]
它是一个字符串的列表或元组。每个字符串是一个字段名,前面带有可选的“-”前缀表示倒序。
前面没有“-”的字段表示正序。使用”?”来表示随机排序

Options.permissions
设置创建对象时权限表中额外的权限。增加、删除和修改权限会自动为每个模型创建。

Options.proxy
如果proxy = True, 作为该模型子类的另一个模型会被视为代理模型。

Options.unique_together
用来设置的不重复的字段组合:
unique_together = ((“driver”, “restaurant”),)
它是一个元组的元组,组合起来的时候必须是唯一的。它在Django后台中被使用,
在数据库层上约束数据(比如,在 CREATE TABLE 语句中包含 UNIQUE语句)。

Options.index_together
用来设置带有索引的字段组合:
index_together = [
[“pub_date”, “deadline”],
]

十六.抽象基类

抽象基类在你将一些共同信息导入到多个其他模型的时候很有用。

你写你的基类,并在Meta类(元类)中设置abstract=True。该模型不用于生成任何数据库表。反而,当抽象基类用于其他模型的一个基类是,它的fields(字段)会被添加到那些子类中。

这个是错误的:抽象基类和其子类拥有同名的字段(Django会报异常)。

一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
from django.db import models

name = models.CharField(max_length=100)

age = models.PositiveIntegerField()

class Meta:

abstract = True

class Student(CommonInfo):

home_group = models.CharField(max_length=5)

上例中,Student模型有3个字段,name,age和home_group.CommonInfo模型不能用于普通Django模型,因为这是个抽象基类。CommonInfo不会生成一个数据库表或者拥有一个管理器,不能被实例化和直接存储。

对于许多用户来说,这种继承模型类型正是你想要的。它提供了在Python级别分解共同信息的一种方法,同时只根据数据库等级的子模型来生成一个数据库表。

###Meta继承:

创建抽象基类的时候,Django 会将你在基类中所声明的有效的 Meta 内嵌类做为一个属性。

如果子类没有声明自己的Meta类,它将继承父类的Meta类。如果子类想要扩展父Meta类,可以子类化。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from django.db import models

class CommonInfo(model.Model):



class Meta:

abstrasct = True

ordering = ['name']

class Student(CommonInfo):



class Meta(CommonInfo.Meta):

db_table = ‘student_info’

Django对抽象基类的Meta类做了一个调整:在安装Meta属性前,设置abstract=False.这意味着抽象基类的子类本身不会自动变成抽象类。当然,你可以通过从其他抽象基类继承的方法来生成一个抽象基类。你只要记住,每次明确地设置abstract=True。

对抽象基类而言,有些属性放在Meta内嵌类中没有意义。例如,包含db_table意味着所有子类(那些没有Meta内嵌类的子类)将会使用相同的数据库表,当然这也不是你想要的。

对于related_name 和 related_query_name要特别小心

当你正在ForeignKey或者MangToManyField中正使用related_name或者related_query_name时,你总要给字段(field)明确一个unique reverse name(唯一反向名称)和query time。这通常会在抽象基类中导致出现问题,因为Django会将基类字段添加进子类当中,而每个子类的字段属性值基本相同。这样,在使用ForeignKey或者ManyToManyField反向指定时,就无法确定指向哪个子类了。

为解决这个问题,当你(仅)在抽象基类中使用related_time或者related_query_name时,部分值应该包含’%(app_label)s’和‘%(class)s’。

‘%(class)s’会被子类名字取代;

‘%(app_label)s’会被子类所在App的名字取代。

举例:

假定有个app common/models.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from django.db import models

class Base(models.Model):

m2m = models.ManyToManyField(

OtherModel,

related_name = "%(app_label)s_%(class)s_related",

related_query_name = "%(app_label)s_%(class)ss",

)

class Meta:

abstract = True

class ChildA(Base):

pass

class ChildB(Base)

pass

在另一个apprare/models.py中:

from common.models import Base

class ChildB(base):

pass

那么,common.ChildA.m2m字段的反向名称common_childa_related,

common_ChildB.m2m字段的反向名称为commom_childb_related;

rare app中,rare.ChildB.m2m字段的反向名称为rare_childb_related.

如果你没有在抽象基类中为某个关联字段定义related_name属性,那么默认的反向名称就是子类名称加上‘_set’,它能否正常工作取决于你是否在子类中定义了同名字段。

例如,上面代码中,如果去掉related_name属性,在ChildA中,m2m字段的反向名称就是childa_set;

而ChildB的m2m字段的反向名称就是childb_set.

###Multi-table继承 多表继承

这是Django支持的第二种继承方式。使用这种继承方式时,同一层级下的每个子model本身是一个model。

每个子model都有自己的数据库表,可单独查询与创建。继承关系在子model和它的每个父类之间采用链接方式。(通过自动创建的OneToOneField)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from django.db import models

class Place(models.Model):

name = models.CharField(max_length=50)

address = models.CharField(max_length=80)



class Restaurant(Place):

serves_hot_dogs = models.BooleanField(default=False)

serves_pizza = models.BooleanField(default=False)

Place的所有字段在Restaurant中都可以使用,尽管数据驻留在不同的数据库表中。所以下面这些都是可能的:

Place.objects.filter(name=”Bob’s Cafe”)

Restaurant.objects.filter(name=”Bob’s Cafe”)

如果你有一个Place,同时也是Restaurant,你可以使用小写的model名称,从Place对象得到Restaurant对象:

p = Place.objects.get(id=12)

If p is restaurant object, this will give the child class:

p.restaurant

Restaurant:…

如果上例中p不是一个Restaurant,(它已经直接有Place对象创建或者是一些其他类的父类)。引用p.restaurtant将抛出Restaurant.DoesNotExist异常:

from myapp.models import Place,Restaurant

p=Place.objects.create(name=’Place’,addres=‘Place’)

p.restaurant

DoesNotExist:Place has no restaurant.

自动创建的Restaurant的OneToOneField字段链接Place如下:

place_ptr = models.OneToOneField(Placemon_delete=models.CASCADE,parent_link=Terue,)

你可以重载Restaurant的字段,通过在自己的OneToOneField中申明parent_link=True。

###Meta和多表继承

在多表继承中,子类继承父类的Meta内嵌类没什么不清楚的。所有Meta选项已经对父类起作用了,再次使用只会起反作用(这与使用抽象基类的情况正好相反,因为抽象基类并没有属于它自己的内容)

待续。。。。



转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 jaytp@qq.com
目录
主站