Django中不溜教程(5)模型层(2)之表关系

前言

我们上一章节主要介绍了定义模型类的字段类型,字段参数,是围绕着单表进行学习的,我们在这一章节会着重介绍Django中的多表操作。
此章节中有对表关系的复习,如果这些对于你过于简单,可通过点击顶部的导航跳跃到你想要知识的位置。

显示sql语句的配置

我们需要知道Django针对数据库提供的是ORM形式的操作,开发者的代码行很少出现直接的sql语句,Django会自动生成并且执行。我们想要知道Django到底执行了什么样的语句,方面我们进行追踪调试。
打开项目的setting.py文件,追加一下代码:

#LOGGING是日志的意思,这段代码无需深究,意思是配置日志输出等级为DEBUG
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}

多对一,一对多

场景

多对一与一对多可以归并成一种场景,只不过立场对象不同,他们的特点是:一张表中有一条记录可以对应另外一张表中的多条记录;但是反过来,另外一张表的一条记录
只能对应第一张表的一条记录,这种关系就是一对多或多对一。

多对一是在软件开发过程中最常见的表关系,也是我们学习的重点。
场景列举:
1用户表和订单表,一个用户可以有多条订单,但是一个订单只能属于某一个用户,用户就会"一",订单是“多”。
2作者表和博客表,一个作者可以写多个博客,但是非协作的博客只能有一个作者
3博客表和评论表,一篇博客可以有多条评论,但是一条评论属于一篇博客
。。。

mysql表中的实现方式

多对一关系在表设计中的实现:首先先确定两张表的角色,属于“一”的表我们也称为主表,属于"多"的表我们也称之为从表或者属表。我们可以通过在从表中添加外键字段指向主表的主键来实现多对一表关系。
举例博客和作者表:
author表:

idnameage

blog表:

idtitlecontentauthor_id

blog表的author_id作为外键指向author的主键id字段

django的实现

django实现多对一并不难,依靠django.db.models.ForeignKey类。它是一种Field字段类型,使用方式也很简单,我们来看一段实例代码:

from django.db import models
#作者表,主表
class author(models.Model):
  # ...定义字段
  
 #博客表,从表
class blog(models.Model):
	#ForeignKey定义外键属性,第一个参数指向主表对应的类,第二个参数指定级联操作
	author = models.ForeignKey(author, on_delete=models.CASCADE)
    # ...定义其他字段
    

注意新增模型只有一定要通过命令重新生成并执行迁移文件,这样才会在数据库中新建数据表,操作流程如有遗忘请参Django中不溜教程(2)快速入门2的内容

数据库表被创建成功之后我们来学习一多对一的api函数,我们在终端内体验下多对一新增数据和获取数据的方式

python manage.py shell #进入Django环境的终端
>>>from manytoone.models import blog,author
>>>a =author(name='fei',age=20,gender='m')
>>>a.save()  #像数据库中新增一条作者记录
>>> #接下来我们要创建一条博客,并且为博客指定作者,也就会博客的外键字段要有值
>>>b=blog(title='hello',content='nihao',author=a)
>>>b.save() #保存成功,注意这里为blog指定的author参数的a对象一定要已经执行过save()函数
>>>
>>>#以上是对象的创建,接下来我们看一下多对一关系在查询时候的方便之处
>>>b.author.name  #根据blog对象获取所属的作者的名字
>>>'fei'
>>>a.blog_set.all() # 根据author对象获取他所创作的所有博客,语法 FOO_set, FOO 即源模型名的小写形式

多对多

场景

一对表中(A)的一条记录能够对应另外一张表(B)中的多条记录;同时B表中的一条记录也能对应A表中的多条记录,这种情况下,A表和B表的关系就是多对多。
显示场景举例:
1用户表和群组表,一个用户可以加入多个群组,一个群组同样拥有多个用户,他们就是对多
2演员表和电影表,一个演员可以参演多个电影,一个电影也需要多个演员共同参演
3

mysql表中的实现方式

多对多在myql中实现起来略复杂,但是也是有固定套路的,只要是多对多我们就使用中间表,在中间表中维护表关系。
拿演员表和电影表举例:
actor表:

idnameage

film表:

idnamepub_date

actor表与film表中只需要各自保存所需字段即可,不需要创建与表关系相关的字段,name他们的关系在额外的一张表中进行维护
actor_film表:

idactor_idfilm_id

我们用一张图来表示他们之间的关系:
在这里插入图片描述

django的实现

Django针对多对多的实现也不难,与多对一有些类似,使用的是 django.db.models.ManyToManyField类。

#model模型类中的定义

class film(models.Model):
    name=models.CharField(max_length=20)
    pub_date=models.DateTimeField(auto_now=True)
  
    
class actor(models.Model):
    name=models.CharField(max_length=20)
    age=models.IntegerField
    #建议表示ManyToManyField字段的名称为复数,表示一个集合
    films=models.ManyToManyField(film)



注意:对于多对多光联关系的两个模型,可以在任何一个模型中添加 ManyToManyField 字段,但只能选择一个模型设置该字段,即不能同时在两模型中添加该字段。一般来讲,应该把 ManyToManyField 实例放到需要在表单中被编辑的对象中。

shell中测试:
别忘了重新生成并运行迁移文件哦!

>>>from manytomany.models  import film,actor
>>> #插入两条电影记录
>>>f1=film(name='love')
>>>f1.save()
>>>f2=film(name='you')
>>>f3.save()
>>>#插入一条演员记录
>>>a=actor(name='you',age=30)
>>>#一定要先保存,才能够关联对象
>>>a.save();
>>>#接下来就可以将将电影指定给演员,绑定他们的关系
>>>a.films.add(f1,f2,f3)
>>>a.films.all()#获取演员参演的所有电影

一对一

场景

一对一关系就是指一张表的一条记录一定只能与另外一张表的一条记录进行对应,反之亦然。多用于将一张字段比较多的表(A),将其中不常用的字段或者可以称为一组的字段独立成一张新的表(B),此时A表和B表就是一对一关系。
比如ser表:

idusernamegenderagetelcityprovinceaddress

其中用户名,性别,年龄属于常用基本信息,电话,城市,省,详细地址为个人的联系方式,不属于基本信息,也不常用,我们就可以把电话,城市,省,详细地址独立出来形成一个独立的表。

一般来说一对一使用较少,因为多对一完全可以代替一对一关系

mysql表中的实现方式

那么我们获得到两张表:用户基本信息表,用户联系方式表,拆分后如下:
user表:

idusernamegenderage

usercontactinfo表:

telcityprovinceaddressuid

usercontactinfo表中的新增的uid字段我们需要着重声明,uid既是当前表的主键,又是指向user表id字段的外键。

django的实现

一对一的实现依靠的是 django.db.models.OneToOneField 实现,使用方式如下:

from django.db import models
class user(models.Model):
    genderchoice = [
        ('m', '男性'),
        ('f', '女性'),
    ]
    username = models.CharField(max_length=20)
    age = models.IntegerField
    gender = models.CharField(max_length=1, choices=genderchoice)


class usercontactinfo(models.Model):
    #指定一对一关系,最终会创建一个字段,此字段既是主键又是外键
    user = models.OneToOneField(user, on_delete=models.CASCADE,primary_key=True)
    tel = models.CharField(max_length=20)
    city= models.CharField(max_length=20)
    province = models.CharField(max_length=20)
    address = models.CharField(max_length=20)

shell中测试:
别忘了重新生成并运行迁移文件哦!

>>>from onetoone.models import user,usercontactinfo
>>>u=user(username='pfdu',gender='m',age=30) #创建一个用户对象
>>>u.save() #插入数据库
>>>ucontactinfo = usercontactinfo(tel='123',province ='henan',city='kf',address='xxxx',user =u)#创建用户联系方式信息表,绑定用户记录
>>>ucontactinfo .save()
>>>#接下来就可以通过一方的对象获取另一方的对象,比如
>>>ucontactinfo.user #根据用户联系方式获取所属的用户记录
>>>u.usercontactinfo#根据记录获取用户联系方式信息记录
>>>

自关联

自关联也叫做递归关系,表现为与自身具有多对一关系的对象。
比如保存省和市的数据表设计,使用在一张表中就可以实现即保存城名又保存省名,表结构如下:

idnamep_id
1北京null
2西城1
3东城1
4朝阳1
5河南null
6开封1
7郑州1
8洛阳1

在一张表中某条记录的外键指向同一张表的另一条记录,就是自关联的多对一关系。
实现方式与普通的多对一实现其实是一样的

class CityAndPro(models.Model):
		name=models.CharField(max_length=10)
		parent =models.ForeignKey('self',  null=True)   #ForeignKey指向自己,使用self

类似场景还有树形结构的菜单表的设计,分为一节菜单和二级菜单的时候也可以使用自关联。

更多

当前章节介绍了表关系和django中对表关系的实现,当然操作表关系的API本章节涉及到的不多,我们接下来会专门有一个针对数据库API的章节。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值