【Django 笔记】模型(2)-- 关系、关联查询、 Manager、Mate选项、原生 SQL

【Django 笔记】模型

 

笔记主要基于官方文档,从中提取要点和记录笔记,关键处包含了官方文档链接。详见官方文档。

官方文档:Django documentation 

博客推荐:Django2.2教程

官方文档模型层:The model layer   模型层

 

目录

1.关系

1.1.关系字段类型

1.2.关联查询(一对多)

1.3.插入、更新和删除

1.4.自关联

2.管理器

3. 元选项

回归原生 SQL


 

1.关系

相关官方文档:关系类型 https://docs.djangoproject.com/zh-hans/2.2/topics/db/queries/#related-objects

https://www.liujiangblog.com/course/django/96

 

1.1.关系字段类型

关系型数据库的关系包括三种类型:

  • ForeignKey:一对多,将字段定义在多的一端中
  •  ManyToManyField:多对多,将字段定义在任意一端中。
  • OneToOneField:一对一,将字段定义在任意一端中。
  • 可以维护递归的关联关系,使用'self'指定,详见"自关联"。

 

1.1.1.一对多ForeignKey

一对多关联

One-to-many relationships多对一的关系,通常被称为ForeignKey外键。外键字段类的定义如下:

class ForeignKey(toon_delete**options)[源代码]

外键需要两个位置参数,一个是关联的模型(被关联的类)和 on_delete 选项。在Django2.0版本后, on_delete 选项为必填。

 

外键要定义在‘多’的一方: 如厂家生产很多车,则外键定义在车

from django.db import models

class Car(models.Model):
    manufacturer = models.ForeignKey(
        'Manufacturer',
        on_delete=models.CASCADE,
    )
    # ...

class Manufacturer(models.Model):
    # ...
    pass

 

若关联的对象在另外一个app中,可以用完整的应用标签显式的指出。

下例假设Manufacturer模型存在于production这个app中,则Car模型的定义如下:

class Car(models.Model):
    manufacturer = models.ForeignKey(
        'production.Manufacturer',      # 关键在这里!!
        on_delete=models.CASCADE,
    )

 

如果要创建一个递归的外键,也就是自己关联自己的外键(自关联),使用下面的方法:

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

核心在于‘self’这个引用。什么时候需要自己引用自己的外键呢?典型的例子就是评论系统!一条评论可以被很多人继续评论,如下所示:

class Comment(models.Model):
    title = models.CharField(max_length=128)
    text = models.TextField()
    parent_comment = models.ForeignKey('self', on_delete=models.CASCADE)
    # .....

注意上面的外键字段定义的是父评论,而不是子评论。为什么呢?因为外键要放在‘多’的一方!

类似的还有自关联的 地区的行政管理、公司部门的上下级部门行政级别管理等系统。

 

外键还有一些重要的参数,参考:外键参数

示例:多对一关联示例

 

 

1.1.2. 多对多ManyToManyField

多对多关联

多对多的字段可以定义在任何的一方,尽量定义在符合人们思维习惯的一方。字段类的定义如下:

class ManyToManyField(to**options)[源代码]

多对多关系需要一个位置参数:关联的对象模型。它的用法和外键多对一基本类似。

class TypeInfo(models.Model):
  # ...
  pass

class NewsInfo(models.Model):
  # ...
  ntype = models.ManyToManyField('TypeInfo') #通过ManyToManyField建立TypeInfo类和NewsInfo类之间多对多的关系

注:在数据库后台,Django实际上会额外创建一张用于体现多对多关系的中间表。默认情况下,该表的名称是“多对多字段名+关联对象模型名+一个独一无二的哈希码”。例如‘author_books_9cdf4’,当然也可以通过db_table选项,自定义表名。

 

多对多还有一些重参数,参考:多对多参数

示例:多对多关联示例

 

1.1.3. 一对一OneToOneField

一对一关联

一对一关系类型的定义如下:

class OneToOneField(toon_deleteparent_link=False**options)[源代码]

一对一关系类似具有unique=True属性的外键关系,但是反向关联对象只有一个。

 

该关系的第一位置参数为关联的模型,其用法和前面的多对一外键一样。

如果你没有给一对一关系设置related_name参数,Django将使用当前模型的小写名作为默认值。

OneToOneField一对一关系拥有和多对一外键关系一样的额外可选参数,只是多了一个parent_link参数。

 

示例:一对一关联示例

 

 

1.2.关联查询(一对多)

 

1.2.1.查询和对象关联的数据

在一对多关系中,一对应的类我们把它叫做一类,多对应的那个类我们把它叫做多类,我们把多类中定义的建立关联的类属性叫做关联属性(关系属性、关系字段)

 

以下例子,假设,一本书(一类BookInfo)对应多个英雄(多类HeroInfo)。

 

由一类的对象查询多类的时候(由一到多的访问语法):一类的对象.多类名小写_set.

一类的对象.多类名小写_set.all()

# 查询id为1的图书关联的英雄的信息
b = BookInfo.objects.get(id=1)
b.heroinfo_set.all()


# 通过模型类查询:
HeroInfo.objects.filter(hbook__id=1)

由多类的对象查询一类的时候:多类的对象.关联属性

多类的对象.关联属性 

# 查询id为1的英雄关联的图书信息
h = HeroInfo.objects.get(id=1)
h.hbook


# 通过模型类查询:
BookInfo.objects.filter(heroinfo__id=1)

由多类的对象查询一类对象的id时候:多类的对象. 关联属性_id

多类的对象. 关联属性_id

h = HeroInfo.objects.get(id=1)
h.hbook_id

 

1.2.2.通过模型类实现关联查询

通过多类的条件查询一类的数据

   一类名.objects.filter(多类名小写__多类属性名__条件运算符=值)

 

通过一类的条件查询多类的数据

   多类名.objects.filter(关联属性__一类属性名__条件运算符=值)

 

Tips:

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

 

例子:

例:查询图书信息,要求图书关联的英雄的描述包含''

BookInfo.objects.filter(heroinfo__hcomment__contains='八')

例:查询图书信息,要求图书中的英雄的id大于3.

BookInfo.objects.filter(heroinfo__id__gt=3)

例:查询书名为天龙八部的所有英雄。

HeroInfo.objects.filter(hbook__btitle='天龙八部')

 

1.3.插入、更新和删除

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

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

 

1.4.自关联

自关联:自关联

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

说明:关系属性使用self指向本类,要求null和blank允许为空,因为一级数据是没有父级的。

要创建一个递归关系 -- 一个与其自身有多对一关系的对象 -- 则使用 models.ForeignKey('self', on_delete=models.CASCADE)

 

举例:地区信息模型类

#定义地区模型类,存储省、市、区县信息
class AreaInfo(models.Model):
    atitle=models.CharField(max_length=30)#名称
    aParent=models.ForeignKey('self',null=True,blank=True, on_delete=models.CASCADE)#关系

 

2.管理器

管理器官方文档:管理器

 

查询时,一般都用到objects,比如:模型类.objects.all(),那objects是一个什么东西呢?

答:objects是Django帮我自动生成的管理器对象默认情况下,Django 为每个模型类添加了一个名为 objects 的 Manager通过这个管理器可以实现对数据的查询。objects是models.Manger类的一个对象。

 

管理器

管理器是Django的模型进行数据库操作的接口,Django应用的每个模型类都拥有至少一个管理器。Django支持自定义管理器类,继承自models.Manager。

 

自定义管理器

当没有为模型类定义管理器时,Django会为每一个模型类生成一个名为objects的管理器,自定义管理器后,Django不再生成默认管理器objects。

继承基类 Manager,在模型中实例化自定义 Manager,你就可以在该模型中使用自定义的 Manager

 

自定义Manager主要用于两种情况

1.改变查询的结果集,修改 Manager 返回的原始 QuerySet比如重写all()方法。

2.向管理器类中添加额外的Manager 方法,如封装方法,操作模型类对应的数据表(增删改查)。

 

 Manager 方法能通过 self.model() 获取所依附的模型类,使用self.model()就可以创建一个跟自定义管理器对应的模型类对象。

在自定义的Manager里使用,这样就避免了模型类名发生变化时,需要改自定义Manager的代码。

 

举例

class BookInfoManager(models.Manager):
    '''图书模型管理器类'''
    # 1.改变原有查询的结果集
    def all(self):
        # 1.调用父类的all方法,获取所有数据
        books = super().all() # QuerySet
        # 2.对books中的数据进行过滤
        books = books.filter(isDelete=False)
        # 返回books
        return books

    # 2.封装方法,操作模型类对应的数据表(增删改查)
    def create_book(self, btitle, bpub_date):
        '''添加一本图书'''
        # 1.创建一个图书对象
        # 获取self所在的模型类
        model_class = self.model
        book = model_class()
        book.btitle = btitle
        book.bpub_date = bpub_date
        # 2.添加进数据库
        book.save()
        # 3.返回book
        return book


class BookInfo(models.Model):
    # ...省略
    objects = BookInfoManager()  # 自定义一个BookInfoManager类的对象

 

模型管理器类和模型类关系

如图:模型类的objects就是模型管理类Manager的实例对象。模型类的实例对象可以通过objects调用Manager的方法...

 

更多Manager详情移步官方文档:https://docs.djangoproject.com/zh-hans/2.2/topics/db/managers/#

 

3. 元选项

官方文档:Meta 选项Model Meta options

相关博文:https://www.liujiangblog.com/course/django/99

 

模型的元数据,指的是“除了字段外的所有内容”,例如排序方式、数据库表名、人类可读的单数或者复数名等等。所有的这些都是非必须的,甚至元数据本身对模型也是非必须的。

 

利用元类Mate指定表名

Django默认生成的表名:

<app_name>_<model_name>  即   应用名小写_模型类名小写 

但在Django中,默认生成的表名如上。当模型名改了之后,对应的表名也会改变,这时用新的表名去找旧的数据就会报错。要表名不依赖于应用和模型类的名字,就需要指定表名。

在模型类中定义一个元类Meta,在里面定义一个类属性db_table就可以指定表名。如下:

# 定义图书模型类BookInfo
class BookInfo(models.Model):
    # ...省略

    # 定义元选项
    class Meta:
      db_table='bookinfo'  # 指定BookInfo生成的数据表名为bookinfo

重新执行迁移之后,表名就是 bookinfo 了。

 

模型中增加元数据

有上面的例子可见,想在模型中增加元数据,方法很简单,在模型类中添加一个子类,名字是固定的Meta,然后在这个Meta类下面增加各种元数据选项或者说设置项

强调:每个模型都可以有自己的元数据类,每个元数据类也只对自己所在模型起作用。

 

可用的元数据选项:参考 Available Meta options

 

 

回归原生 SQL

若你发现需要编写的 SQL 查询语句太过复杂,以至于 Django 的数据库映射无法处理,你可以回归手动编写 SQL。Django 针对编写原生 SQL 有几个选项;参考 执行原生 SQL 查询

最后,Django 数据库层只是一种访问数据库的接口,理解这点非常重要。你也可以通过其它工具,编程语言或数据库框架访问数据库;Django 并没有对数据库数据库做啥独有的操作。

 

-----end-----

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值