一些废话:
本人大二,最近上了Web开发课,以学习django为主。
首先是觉得对开发有兴趣,另外感觉django的知识比较零碎,所以开创了[Ylxn的Django上课笔记]栏目。所有内容都仅个人学习总结用,毕竟初学会有很多问题,如有错误欢迎指出,感激不尽!
多对一关系
首先在model.py添加如下代码
class banj(models.Model):
mc = models.CharField(max_length=8)
def __str__(self):
return self.mc
class xues(models.Model):
xm = models.CharField(max_length=8)
bj = models.ForeignKey(banj,on_delete=models.CASCADE,null=True) #外键,关联班级
def __str__(self):
return "%s %s" %(self.xm,self.bj)
可以看到:我们建立了两个数据库,
一个是banj(班级);
一个是xues(学生),并且与banj外连接
这样就建立了一个最简单的多对一关系:一个班级可以对应对多个学生,但是一个学生只能在一个班级里面,(我们下面还会介绍多对多关系);
然后django是需要手动在终端执行数据库迁移指令的,需要非常熟悉
python manage.py makemigrations
python manage.py makemigrate
现在我们给刚刚创建的班级和学生两个数据库加入实例变量
(myvenv) D:\mytest\chapter4\chapter4>python manage.py shell
Python 3.9.2 (tags/v3.9.2:1a79785, Feb 19 2021, 13:44:55) [MSC v.1928 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from faqs.models import *
>>> b3 = banj(mc='3班') #创建banj类的对象,未保存
>>> x3 = xues(xm='wangwu',bj=b3) #创建x3,并且引用了没有保存的实例变量b3
>>> x3.save()
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "D:\mytest\myvenv\lib\site-packages\django\db\models\base.py", line 778, in save
self._prepare_related_fields_for_save(operation_name="save")
File "D:\mytest\myvenv\lib\site-packages\django\db\models\base.py", line 1093, in _prepare_related_fields_for_save
raise ValueError(
ValueError: save() prohibited to prevent data loss due to unsaved related object 'bj'.
尝试保存x3时发生了报错,是因为x3外连接的实例变量b3没有保存,我们保存b3再试试:
>>> b3.save()
>>> x3.save()
刷新一下数据库看看效果:
用代码看一下班级里的学生:
>>> b = banj.objects.get(id=1)
>>> b
<banj: 1班>
>>> b.xues_set.all()
<QuerySet [<xues: zhangsan 1班>]>
以一班为例,我们看见一班中只有一个学生 zhangsan
代码中,b代表1班,
xues_set.all()代表列举所有学生的集合,如果不加all实际上就是一个对象
>>> x3=b.xues_set.create(xm='HanMeimei')
>>> x3.id,x3.xm
(4, 'HanMeimei')
这里和以前明显不同的地方在于没有写x3.save()
而且数据库也是更新好了的:
使用object或者set都是直接作用于数据库,而普通的
x3 = xues(xm='ylxn',bj=b)
是一种python语言,x3是python语言中的一种类,这样才需要save
可以通过学生对象来访问关联的班级对象,我们通过班级来创建学生
>>> b
<banj: 1班>
>>> xx = b.xues_set.create(xm='XiaoDeng')
>>> xx.id,xx.xm,xx.bj.id,x3.bj.mc
(6, 'XiaoDeng', 1, '2班')
add调用方法:
>>> b2.xues_set.add(xx)
>>> xx.id,xx.xm,xx.bj.id,x3.bj.mc
(6, 'XiaoDeng', 2, '2班')
班级是学生的外键,可以通过学生对象访问关联的班级对象,通过班级b创建学生xx
b.xues_set用于访问关联对象的模型管理器
调用add()方法创建关系/更改原本的关系
从结果上看:学生XiaoDeng从创建的1班编程了2班
remove删除关系:
再看一下xues数据库的定义:
class xues(models.Model):
xm = models.CharField(max_length=8)
bj = models.ForeignKey(banj,on_delete=models.CASCADE,null=True) #外键,关联班级
def __str__(self):
return "%s %s" %(self.xm,self.bj)
这里需要强调一下:
1:如果要用到remove,创建数据库的时候,必须要加上null = True,否则会发生如下报错:
django.db.utils.IntegrityError: NOT NULL constraint failed: faqs_xues.bj_id
这是因为:只有在把ForeignKey字段的null选项设置为True时,才允许删除关系
2:banj实例对象和xues实例对象必须要是同一类型,换句话说,我们这里用到的类型有两种,一种是数据库里的对象,一种是python里的对象,如果对象类型不一致也会报错:
AttributeError: 'RelatedManager' object has no attribute 'remove'
我们可以在终端输入下面代码来查看类型
实例名字__dict__
好的,下面是删除的代码:
>>> from faqs.models import *
>>> b2 = banj.objects.get(id=2)
>>> b2
<banj: 2班>
>>> xx = xues.objects.get(id=6)
>>> xx
<xues: XiaoDeng 2班>
>>> b2.xues_set.remove(xx)
删除关系后,,除了指定数据被改成null,之前其他的数据都会被保留
还可以通过clear()方法来清空指定的所有数据,规则同上
>>> b2.xues_set.clear()
这里b2就是二班,执行以后二班里所有的学生,他们的外键班级全部会变成<null>
多对多关系
这里我们在models里添加了新的数据库:
class shet(models.Model):
mc = models.CharField(max_length=8)
def __str__(self):
return self.mc
class stus(models.Model):
xm = models.CharField(max_length=8)
shets = models.ManyToManyField(shet)
def __str__(self):
return self.xm
给数据库创建实例:
(myvenv) D:\mytest\chapter4\chapter4>python manage.py migrate
Apply all migrations: admin, auth, contenttypes, faqs, sessions
Python 3.9.2 (tags/v3.9.2:1a79785, Feb 19 2021, 13:44:55) [MSC v.1928 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from faqs.models import *
>>> s1 = shet(mc='rds')
>>> s1.save()
>>> s2= shet(mc='wxs')
>>> s2.save()
>>> s3 = shet.objects.create(mc='dms')
使用模型构造函数或者create()方法创建学生对象,接着,我们给社团创建关系关联社团
>>> x1.shets.add(s1,s2)
>>> x1.shets.add(s3)
>>> x1.shets.add(s2)
通过学生对象来创建社团对象:
>>> x2 = stus.objects.create(xm='LiuMing')
>>> x2.shets.all()
<QuerySet []>
>>> x2.shets.create(mc='sgs')
<shet: sgs>
>>> x2.shets.all()
<QuerySet [<shet: sgs>]>
我们先创建了一个新的学生x2,名字交LiuMing,然后通过shets.all()方法可以看到,还没有跟任何社团有管理,所有set为空;
然后用create创建社团sgs,并且与x2建立关联;
再查看关联,就能看见二者已经建立了关联了!
py版本:3.9.2
pycharm:专业版2023.3.3
总结到这里结束,如果你是路人,很感谢你能看到这里,有问题欢迎交流!