进阶Django(三):模型外键、多对多关系、自关联外键及Meta类

目录

前言

模型中的映射关系

1 物理外键与逻辑外键

2 Django中的外键(一对一、一对多关系)

3 Django中的多对多关系

3.1 使用ManyToManyField自动建立多对多关系

3.2 另一种建立多对多表的方式

3.3 多对多关系的建立与查询

4 自关联外键

5 外键删除时

Model的Meta内部类

使用Model时遇到的一些问题

1 使用mysql报错 Did you install mysqlclient?

2 You are trying to add a non-nullable field 'xxx' to xxx


前言

本文为Django框架下Model模块的进阶教程,承接的是本专栏的文章《初识Django(七):模型》。本文主要介绍的是Model下外键(一对一、一对多)、多对多关系的使用和Meta类的使用,以及解决一些疑难问题。

模型中的映射关系

1 物理外键与逻辑外键

外键是表中一个特殊的字段,被用于与其他表建立关系。

外键分为物理外键与逻辑外键两种,物理外键在数据库中定义,其级联关系由数据库本身维护;而逻辑外键的关系由自定义的代码维护。由于物理外键会强制要求数据库在删除具有外键的记录时检查数据,在数据量大的情况下会造成数据库资源的浪费,加上mysql对外键的设计不合理,所以一般不建议使用物理外键。

2 Django中的外键(一对一、一对多关系)

Django中的ForeignKey为逻辑外键当你在Django中声明一个列为ForeignKey时,其实际上存入的是连接到的表的主键,并为此列建立一个索引。ForeignKey的使用如下例所示:

class ForeignModel(models.Model):

    data=models.CharField(max_length=100)

class ExampleModel(models.Model):

    id=models.CharField(default=CALLABLE_FUNC) #置为随机数函数

    username=models.CharField(max_length=30,blank=True)

    data=models.ForeignKey(ForeignModel)

如果要建立的两张表记录是一对一关系,记得在外键上添加unique=True属性,当记录的是一对多关系时,则需要在“多”的表中建立外键。

3 Django中的多对多关系

事实上,它原理上和一般的数据库多对多关系的实现并无二致。但在Django中,你可以直接使用ManyToManyField声明一个多对多字段,django会自动为你创建一张记录多对多关系的表。

3.1 使用ManyToManyField自动建立多对多关系

一个例子:

class Example1Model(models.Model): 

    data1=models.CharField(max_length=50)

class Example2Model(models.Model):

    data2=models.CharField(max_length=50)

    release=models.ManyToManyField(Example1Model) #多对多关系

运行migrate命令后,查看数据库,可以发现生成了一个app名_example2model_release表,即为记录多对多关系的表。

3.2 另一种建立多对多表的方式

使用Django ManyToMantField字段全自动建立第三张表总是差点味道,也不方便维护,那么,为何不直接将第三张表写成一个模型类呢?这种方式的扩展性更高,而且对强迫症非常友好^ ^。

手动书写联系表,然后在ManyToManyField字段中用through参数指定django使用此联系表做映射,如下所示:

class Example1Model(models.Model): 

    data1=models.CharField(max_length=50)

class Example2Model(models.Model):

    data2=models.CharField(max_length=50)

    release=models.ManyToManyField(Example1Model,through="Model1_Model2_Release") #多对多关系

class Model1_Model2_Release(models.Model):

    model1=models.ForeignKey(Example1Model,on_delete=DO_NOTHING)

    model2=models.ForeignKey(Example2Model,on_delete=DO_NOTHING)

3.3 多对多关系的建立与查询

请看以下代码:

e1=Example1Model.objects.create(data1="1234")

e2=Example2Model.objects.create(data2="5678")

#分别创建两个实例

e2.release.add(e1) 

#使用add直接添加对象建立映射关系

e2.release.all()

#正向查询 ,只需要引用ManyToManyField字段

#=> <QuerySet [<Example1Model: Example1Model object (1)>]>

e1.example2model_set.all()

#反查 ,example1model为被查询的类名全小写(即使是django官网那边也没写这个_set怎么来的,我只能自己写了一遍代码确认这玩意- -)

#=> <QuerySet [<Example2Model: Example2Model object (1)>]>

请注意反查引用的字段为[被查询的模型类全小写_set]

4 自关联外键

有时候会发生这样的情况:表中的一条记录与同一张表中的另一条记录相关联,这种情况就叫做自关联。

自关联的三种关系写法与上文相同,只是将引用的类名改成self即可。

5 外键删除时

对于外键而言,由于其引用的是另一条数据库记录,故而不得不考虑一个问题:当它所引用的记录被删除时,它本身所处的记录又该如何?由于一对一、一对多、多对多关系中都需要用到外键,所以这也是上面这些关系中需要共同考虑的内容。

我们在声明外键时,必须设置一个on_delete参数,通过这个参数决定Django在外键依赖的记录删除时会如何处理这个外键对应的数据。

这个参数有以下几个取值:

  • CASCADE:级联删除,当被引用记录删除时,本记录也删除
  • DO_NOTHING:什么也不做
  • SET_NULL:设为空
  • SET_DEFAULT:设为默认值
  • PROTECT:保护模式,当删除引用记录时,会报错
  • SET():设置一个对象,其中填写一个callable对象(比如说一个方法,返回一个默认模型对象)

Model的Meta内部类

如果说模型中字段的参数是对这个字段的设置,那Meta类就是对整个模型的设置。我们可以通过在模型类中建立Meta类并声明特定名称的字段来调整模型。

下方列出一些常用的Meta字段及其意义:

class ExampleModel(models.Model):

    id=models.CharField(default=CALLABLE_FUNC) #置为随机数函数

    username=models.CharField(max_length=30,blank=True)

    class Meta():

        db_table="声明在数据库中对应的表名,不声明django会自动命名为app名_类名"

        app_label="这个字段仅在你的模型类不在默认的models.py文件内,用于指定此模型所属的app,内容为所属app的名字"

        get_latest_by="这个字段指示django的get_latest()按照哪个字段查询。应为一个模型字段名,此字段为DateField或者DateTimeField"

        managed="Boolean。当其为真,django按照Model类修改数据库表,当其为假,django不会进行这些操作。"

        ordering="这个字段指示django返回的数据按照哪个字段排序。为一个DateField或DateTimeField。"

        verbose_name="此模型的别名。这个字段也可用于模型中的字段(有点拗口,这个选项也可以在模型中的列名中单独设置,这里设置的是表的别名,那里设置的是列的别名)。"

使用Model时遇到的一些问题

1 使用mysql报错 Did you install mysqlclient?

发生在manage.py的makemigrations命令中。这问题呢,是一个连环坑。

最开始的报错图如下所示:

意思是我们没有安装mysqlclient,第一反应肯定是打开命令行pip安装一下包,但pip安装又会报错,说打不开文件“mysql.h”。pip安装不成,只能自己去下whl文件安装了。

下载地址如下所示:

https://www.lfd.uci.edu/~gohlke/pythonlibs/#mysqlclient

下载后以安装whl文件的方式安装完毕再次运行,问题解决。

2 You are trying to add a non-nullable field 'xxx' to xxx

这个其实也不算报错,但是需要使用者注意。即使你确定这个字段在后续生成记录时始终不为空,也最好为其设置一个默认值,否则在为表增加字段时django也会强制你添加一个值。

猜你喜欢

转载自blog.csdn.net/qq_34013974/article/details/122364564