Django-4:django模型层ORM-1
ORM-1
一、如何操作数据库
用户注册之后,用户名密码等关键信息需要保存,而这些数据就存储在数据库中。
传统的操作数据库方式无非就三种:
- 一、接显示器本地登陆winserver或者linux系统,linux的话下一步就是mysql -u用户名 -p密码 -h主机,通过敲命令的方式进入、数据库,随后使用SQL语句进行增删改查等操作。
- 二、利用Xshell等远程链接客户端,直接连接到mysql服务器,或者是连接到“跳板机/堡垒机”,随后在跳板机上使用mysql命令,来连接进数据库。
- 三、在前面的方法之上,利用mysql font、Navicat等可视化软件连接到数据库,随后通过鼠标点点的方式来进行库和表的操作,无需SQL命令。
由此看来mysql font、Navicat等可视化软件,相对于传统的方式还是很好用的,毕竟一些简单的增删查改不需要再书写复杂的SQL语句。
而在我们当前的环境下,无需另外下载,pycharm自带这些功能。
另外:
- 对于数据库的操作应该是由代码来执行的,总不可能说,有一个用户注册,那我们就赶紧在数据库的表中插一条数据吧。
- 所以我们django项目也需要连接到数据库,随后借助ORM框架将SQL转换成类、对象、属性来使用,这样我们无需书写原生SQL,直接可以由python代码实现对数据库的操作。
1.1 pycharm链接数据库
pycharm可以充当很多款数据库软件的客户端,可通过在pycharm中进行配置,实现数据库的可视化。
一、MySQL服务器初始化
-
MySQL服务器中,新建了一个名为Python的库,随后可以验证是否可以查询到该库
create database Python character set utf8; GRANT ALL PRIVILEGES ON python.* TO 'pythoner '@'%' IDENTIFIED BY 'pythoner_of_password' WITH GRANT OPTION; flush privileges; ''' 1.创建了个Python库。 2.创建了个用户名,可通过任意主机连接到Python库,操作库中所有表。 用户名:pythoner 密码:pythoner_of_password '''
二、pycharm安装驱动,链接MySQL
具体配置如下:
- **第一步:**找到pycharm中链接数据库的工具

如果按照上述方法都没用,则安装插件,如果还不行就重装pycharm

- 第二步:选择对应数据库,如mysql、mariadb
- 第三步:如果有感叹号提示,那么说明需要先下载驱动

- 第四步:填写数据库信息,链接数据库。

-
第五步:当不显示数据库的所有库时,点击“…”选中。
选中需要使用的库,在pycharm中展示的库,就是数据库服务器中的库。

pycharm配置完成之后,可以作为快速查询数据库数据的一个工具,后面操作数据库都是用的代码(orm)。
1.1.1 附:安装驱动报错
现象:
- 如下图,安装驱动时,报错下载失败。

解决方案
- 报错不是说这个链接的插件下载失败嘛,那我们可以自行下载,然后手动指定驱动位置。
第一步:
-
先按照链接进行下载
https://repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.25/mysql-connector-java-8.0.25.jar
第二步:
-
手动指定驱动位置
1.2 django链接数据库
django默认使用的是一个sqlite3轻量数据库,所以我们把配置文件中,数据库的部分进行更改即可。
-
django连接数据库,默认用的是mysqldb模块,但是该模块的兼容性不好,后续需要手动改为用pymysql模块。
另外sqlite3这个小型数据库会有很多的一些BUG,所以尽量该用其他数据库。
第一步:
-
修改django默认数据库。
# 默认用的是sqkite3 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', #改为mysql 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), #注释掉 } }
第二步:
-
补充库名、登录用户、密码、IP端口等信息,格式为字典
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', #补充上基本信息 'NAME': '库名', 'USER':'登录用户', 'PASSWORD':'密码', 'HOST':'IP地址', 'PORT':3306, 'CHARSET':'utf8' } }
> 'ENGINE': 'django.db.backends.mysql'
>
> - 如果使用的是mariadb数据库,这里依旧.mysql,不影响连接。
**第三步:**
- 代码声明
```python
'''
django连接数据库,默认用的是mysqldb模块,但是该模块的兼容性不好,需要手动改为用pymysql模块
'''
# 在项目名下的init,或者任意的应用名下的init文件中,书写以下代码即可。
import pymysql
pymysql.install_as_MySQLdb()
1.3 ORM初识
简单来说:
- ORM的作用,就是可以让我们无需写原生SQL语句,就可以完成对数据库的各种操作,而且还省略了一些SQL优化的工作,提高了程序的开发效率
ORM:对象关系映射
- 在模板层models.py中,定义的类 ----> 等于数据库中的表。
- 定义的对象 ----> 等于数据库中的每一行数据。
- 定义的对象属性 ----> 等于数据库中表的字段。
ORM的一些简单操作会在本文章中第二章以后进行介绍,剩下的会在路由层的知识点全部介绍完毕之后,再做补充。
二、Django ORM创建表
本章节主要介绍ORM如何创建表,以及表的字段
2.1 创建表和字段
代码示例:
-
应用app_01下的models.py文件
from django.db import models # Create your models here. # 书写类,类就等于表,类中的对象等于字段,固定写法,继承models.Model class User(models.Model): id = models.AutoField(primary_key=True) username = models.CharField(max_length=32) password = models.IntegerField()
这样,一个User表就定义好了(此时还没同步到数据库),同时这个表中有三个字段,分别是id、username、password。
那么这三个字段都是用不同的方法,不同的属性来创建的,那么这些都代表什么意思呢?
2.1.1 字段的定义及属性
关于更多,请见。。。。
以2.1章节中的代码为例:
一、id字段
id字段:
id = models.AutoField(primary_key=True)
- models.AutoField :表示创建的字段为自增字段
- primary_key : 表示是否为主键,值为True表示设置主键
二、username字段
username字段:
username = models.CharField(max_length=32)
- models.CharField : 表示创建的该字段,在插入数据时的数据类型必须为char。
- CharField在调用时有一个必传参数max_length,不然会报错
- max_length参数表示最多不超过多少char(字节)
三、password字段
password字段:
password = models.IntegerField()
- models.IntegerField: 表示创建的该字段,在插入数据时的数据类型必须为int。
四、其他补充
补充
price = models.DecimalField(max_digits=8,decimal_places=2)
DecimalField 多用于创建小数字段
max_digits : 表示小数总共多少位
decimal_places :表示小数点后占几位。
总结:
- 常用的创建字段方式有四种,models.AutoField、models.CharField、models.IntegerField、DecimalField
- 其中models.CharField必须设定最大是多少字节
字段的一些常用属性
补充:
1. verbose_name该参数用来对字段的解释,例如:
id = models.AutoField(primary_key=True,verbose_name='主键')
2. 由于一张表中必须要有一个主键字段,并且一般情况下都叫id字段,
所以orm当你不定义主键字段的时候,orm会自动创建一个名为id主键字段,
也就意味着,后续在创建模型表的时候如果主键字段名无特殊要求,就叫做id,那么主键字段可以省略不写。
3. 该字段可为空
null = True
4. 该字段的默认值
default = '默认值'
2.2 数据库迁移
同步到数据库,非常重要!!!
一、数据库迁移命令
-
python3 manage.py makemigrations # 或 python manage.py makemigrations
将操作记录记录到小本本上(migrations文件夹)
二、将操作同步到数据库中
-
python3 manage.py migrate # 或 python manage.py migrate
将操作真正的同步到数据库中
什么情况下需要使用该命令?
只要修改了models.py中,跟数据库相关的代码,就必须重新执行上述的两条命令
当前项目中,应用名为app_01,那么我们创建的表就为app_01_user,这么做有一个好处,可以防止重复。
- 其他表的作用在后续章节会陆续补充
![]()
三、ORM字段的增删改查
在二章节中,我们知道了如何创建表、定义表字段,以及如何同步到数据库,那么章节将详细介绍如何对表的字段,进行增删改。
3.1 增加字段
方法:
'''
1.直接增加,如:
'''
class 表名(models.Model):
# 略
字段 = models.IntegerField()
# 略
试想一下,现在有一个表,字段有ORM自动创建的ID字段,以及我们模型层定义的name、age字段,并且还插入了一些数据。
如果此时添加一个字段为addr,那么会是什么情况呢?
id name age addr 1 张三 29 2 李四 37
因为新增的addr字段,如果没有默认值或者允许为空,那么就会出现下列报错:
解决方法:
增加字段时,指定该字段可为空或设置默认值即可
-
示例:
# 传入参数 null = True # 允许为空 default='默认值' # 设置默认值
info = models.CharField(max_length=32,verbose_name='个人简介',null=True) hobby = models.CharField(max_length=32,verbose_name='兴趣爱好',default='study')
3.2 删除字段
方法:
- 非常简单粗暴,直接将模型层models.py中的字段代码注释掉,随后同步数据库即可
示例:
-
注释掉不想要的字段
class User(models.Model): username = models.CharField(max_length=30,verbose_name='用户名') age = models.IntegerField(verbose_name='年龄') # info = models.CharField(max_length=32, verbose_name='个人简介', null=True) hobby = models.CharField(max_length=32, verbose_name='兴趣爱好', default='study')
-
执行数据同步命令
python manage.py makemigrations python manage.py migrate
表内该字段对应的所有数据,会随着一并删除。
3.3 更改字段
方法:
- 增加字段与删除字段相结合。
- 先注释掉不需要的字段,随后再书写想要的字段
- 这个过程中会造成数据丢失
四、ORM数据的增删改查
本章节将介绍如何通过ORM对数据进行增删改查
- 依旧是暂时了解一点,后续补充连表查询F与Q查询等。
模板层负责建立与数据库之间的关系,所以获取、添加、修改、删除数据这些操作,都是要在视图层去完成操作的。
在查找视图层书写查询数据的代码时,第一步需要现将应用下的models.py作为模块导入到views.py文件。
# views.py文件
from 应用名 import models
4.1 查找数据
格式:
-
# 全部取出 models.类.objects.all() # 不写查询条件表示数据全部取出 models.类.objects.filter() # 查询指定条件的数据 models.User.objects.filter(username='张三') # 这里的username数据库表中的字段名 # filter可以有多个条件,逗号隔开,关系为and,也就是寻找条件都符合的。 models.User.objects.filter(username='张三',id='2',password='123')
filter、all查询的返回值
-
返回值为QuerySet对象(列表套字典的形式)
<QuerySet [<User: User object>, <User: User object>]>
-
改返回值中的的每个元素为用户对象,获取用户对象的方法:
models.User.objects.filter(password=123)[0] models.User.objects.filter(password=123).first() ''' 此时会返回QuerySet对象中的第一个用户对象,即<User: User object> 拿到用户对象后,可通过.字段名 的方式来获取该用户对象,存储在数据库中的值。 不推荐使用索引的方式,推荐使用first() ''' 如: models.User.objects.filter(password=123)[0].username models.User.objects.filter(password=123,id=1).first().password
应用案例:登录验证
需求:
- 登陆页面输入用户名和密码进行提交。
- 后端将提交的数据进行校验,当用户名和密码均存在于数据库的同一条数据时,返回登陆成功。
- 如果输入的用户名和密码未在数据库中有记录,则返回用户名或密码错误
'''
1.判断用户的请求,为get请求返回login页面,为post请求则进行判断。
2.获取用户提交的信息。
3.获取数据库中的信息。
4.进行比对。
'''
def login(request):
from app_01 import models
if request.method == 'POST': # 当请求为post时进行数据处理
'''获取用户输入数据'''
uname = request.POST.get('username') # 此处的username为,前端input标签的name属性
passwd = request.POST.get('password')
'''获取数据库中的数据'''
res = models.User.objects.filter(username=uname) #这里的username为表中的字段名
user_obj = res[0]
# 这里推荐使用 res.first()
# user_obj为数据对象,可通过 .字段 的方式获取数据,如:user_obj.password
'''进行数据对比'''
if user_obj:
if passwd == str(user_obj.password):
# 需要注意的是,用户在前端输入的内容为str,如果数据库中的密码字段为int,那么需要考虑数据类型的转换
return HttpResponse('登录成功')
else:
return HttpResponse('密码错误')
else:
return HttpResponse('用户不存在')
return render(request, 'login.html') # 当用户为get请求时,返回login页面
4.1.1 补充:pk
当需要依据主键值进行查询时,可以使用“pk”来代指,这样不管主键是id还是uid还是userid,都可以使用"pk"表示。
models.User.objects.filter(pk=1)
'''
查询user表中,主键id值为1的数据。
'''
4.2 增加数据
格式:
-
from 应用名 import models models.类.objects.create(字段1='值',字段12='值', .....)
返回值:
- create()会有返回值,返回值为创建的用户对象,4.1章节中的filter和all,用取出用户对象。
- 有了用户对象之后,同样的可以通过**.sql字段名**的方式,获取数据,如:res.username,其中username为数据库中的字段名
第二种添加数据的方法:(了解即可)
user_obj = models.User(字段1='值',字段12='值', .....) # 实例化对象,此时并没用到ORM
user_obj.save() # 保存数据
应用案例:注册
路由层urls.py
from django.conf.urls import url from django.contrib import admin from app_01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), # 登陆 url(r'login/',views.login), # 注册 url(r'register/',views.register), ]
视图层views.py
def register(request): from app_01 import models if request.method == 'POST': '''获取表单输入的数据''' uname = request.POST.get('Username') # 这里的Username是input表单name属性 passwd = request.POST.get('Password') '''新建用户对象,并添加到数据库''' res = models.User.objects.create(username=uname,password=passwd) #这里的username为数据库的字段名。 return HttpResponse('注册成功,用户:'+res.username) # res.username获取刚刚用户数据对象的username字段值 return render(request, 'register.html')
模板层templates目录下的HTML文件
<!--register.html--> <script src="/static_file/js/jquery.min.js"></script> <script src="/static_file/js/bootstrap.min.js"></script> <link rel="stylesheet" href="/static_file/css/bootstrap.css"> <div class="container"> <div class="row"> <div class="col-md-8 col-md-offset-2"> <h1 class="text-center">Register</h1> <br> <form class="form-horizontal" action="" method="post"> {% csrf_token %} <div class="form-group"> <label for="ipt_uname" class="col-sm-2 control-label">Uname</label> <div class="col-sm-10"> <input type="text" class="form-control" id="ipt_uname" placeholder="Uname" name="uname"> </div> </div> <div class="form-group"> <label for="inputPassword3" class="col-sm-2 control-label">Password</label> <div class="col-sm-10"> <input type="password" class="form-control" id="inputPassword3" placeholder="Password" name="upassword" > </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-success">Register</button> </div> </div> </form> </div> </div> </div>
最终效果展示:

4.3 修改与删除数据
修改/更新:
-
update()
models.User.objects.filter(password='123').update(hobby='懒') # 将所有密码为123的数据对象,批量的把hobby字段值改为'懒' # 其中User为models.py中创建的表(类)
返回值为影响的行数。
删除:
-
delete()
models.User.objects.filter(id=9).delete() # 将id为9的数据删除
返回值同样为受到影响的行数,如:(2, {‘app_01.User’: 2}) 意思就是2行收到delete操作的影响。
应用案例:编辑/删除用户列表
实现效果:
- 通过点击**<编辑>和<删除>**这两个按钮,实现对后端数据库中的用户数据进行展示、更改、删除。

思路:
一、实现html页面展示数据。
1.通过all()或者filter()获取数据库数据,拿到queryset对象。
2.通过render(request,'xxx.html',locals()),将数据交给前端来使用。
3.利用模板语法的for循环,循环得到数据对象,再用数据对象.方法 (方法名为数据库中的字段名) 的方式拿到后端数据
二、实现编辑功能。
'''
实现编辑功能会遇到的问题1:
数据有很多,用户可以点击第一条数据的编辑按钮,也可能会点击第三条数据的,那么我们怎么知道用户点击的是哪一行的
'''
解决方法:
1.将编辑标签改为A标签,href属性为编辑HTML页面+?+参数的形式,参数为当前数据的ID值
如:<a href="/edit_user/?user_id={{ user_obj.id }}">编辑</a>
2.之后用户点击按钮按钮时,会跳转到edit_user接口对应的视图函数,?问号后面的参数不参与路径匹配。
3.随后在视图函数中利用request.GET 来获取跳转之前用编辑按钮所在行的ID字段值。
4.拿到ID值之后,通过filter过滤,将需要被修改的数据展示在编辑页面,等待用户修改。
'''
实现编辑功能会遇到的问题2:
用户在编辑页面上修改并提交之后,如何定位到数据库中的数据呢。
'''
解决办法:
6.可以利用之前提取到的ID值
7.之后通过update的方式进行修改。
8.利用redirect,重定向到主页面。
三、实现删除功能。
9.逻辑同上,只不过不需要再单独创建一个html页面了。
演示效果:

源码
视图层views.py
''' 获取用户列表 ''' def get_userlist(request): data_queryset = models.User.objects.all() # 将queryset对象传递给html页面 return render(request,'userlist/userlist.html',locals()) ''' 编辑用户信息 ''' def edit_userdata(request): # 获取需要修改的id edit_userid = request.GET.get('user_id') ''' 编辑按钮会携带参数,参数为user_id=被修改数据的id 所以可以根据这个id来确定是哪个数据要进行修改 ''' # 当表单提交时,获取表单中的信息,随后更新数据 if request.method == 'POST': ipt_name = request.POST.get('name') ipt_age = request.POST.get('password') ipt_hobby = request.POST.get('hobby') # 批量更新 models.User.objects.filter(id=edit_userid).update(username=ipt_name,age=ipt_age,hobby=ipt_hobby) ''' 筛选出所有id等于edit_userid的数据,随后批量更新。 ''' # 重定向,返回到首页列表 return redirect('/userlist/') # 当表单为get请求时,将需要被修改的数据从数据取出,并渲染到页面上便于修改 edit_user_data = models.User.objects.filter(id=edit_userid).first() return render(request,'userlist/edit_user.html',{'edit_user_data':edit_user_data}) ''' 删除用户数据 ''' def dele_userdata(request): edit_userid = request.GET.get('user_id') models.User.objects.filter(id=edit_userid).delete() return redirect('/userlist/') ''' 添加用户数据 ''' def add_user(request): if request.method == 'POST': ipt_name = request.POST.get('name') ipt_age = request.POST.get('password') ipt_hobby = request.POST.get('hobby') models.User.objects.create(username=ipt_name,age=ipt_age,hobby=ipt_hobby) return redirect('/userlist/') return render(request,'userlist/add_user.html')
路由层urls.py
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'userlist',views.get_userlist), url(r'edit_user',views.edit_userdata), url(r'delete_user',views.dele_userdata), url(r'add_user',views.add_user), ]
模型层models.py
from django.db import models # Create your models here. class User(models.Model): username = models.CharField(max_length=30,verbose_name='用户名') age = models.IntegerField(verbose_name='年龄') hobby = models.CharField(max_length=32, verbose_name='兴趣爱好')
注意要执行数据库同步命令
模板层
- userlist.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="/static_file/js/jquery.min.js"></script> <script src="/static_file/js/bootstrap.min.js"></script> <link rel="stylesheet" href="/static_file/css/bootstrap.css"> </head> <body> <div class="container"> <div class="row"> <div class="col-md-8 col-md-offset-2"> <h1 class="text-center">用户列表</h1> <br> <a href="/add_user/"><button class="btn btn-success btn-xs">新增数据</button></a> <table class="table table-striped table-hover"> <thead> <tr> <th>UID</th> <th>Username</th> <th>Age</th> <th>Hobby</th> <th>Action</th> </tr> </thead> <tbody> {% for user_obj in data_queryset %} <tr> <td>{{ user_obj.id }}</td> <td>{{ user_obj.username }}</td> <td>{{ user_obj.age }}</td> <td>{{ user_obj.hobby }}</td> <td> <a href="/edit_user/?user_id={{ user_obj.id }}" class="btn btn-primary btn-xs">编辑</a> <a href="/delete_user/?user_id={{ user_obj.id }}" class="btn btn-danger btn-xs">删除</a> </td> </tr> {% endfor %} </tbody> </table> </div> </div> </div> </body> </html>
- edit_user.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="/static_file/js/jquery.min.js"></script> <script src="/static_file/js/bootstrap.min.js"></script> <link rel="stylesheet" href="/static_file/css/bootstrap.css"> </head> <body> <div class="container"> <div class="row"> <div class="col-md-8 col-md-offset-2"> <h1 class="text-center">编辑</h1> <br> <form class="form-horizontal" action="" method="post"> {% csrf_token %} <div class="form-group"> <label for="ipt_uname" class="col-sm-2 control-label">Uname</label> <div class="col-sm-10"> <input type="text" class="form-control" id="ipt_uname" placeholder="姓名" name="name" value="{{ edit_user_data.username }}"> </div> </div> <div class="form-group"> <label for="ipt_passwd" class="col-sm-2 control-label">Age</label> <div class="col-sm-10"> <input type="text" class="form-control" id="ipt_passwd" placeholder="年龄" name="password" value="{{ edit_user_data.age }}" > </div> </div> <div class="form-group"> <label for="ipt_hobby" class="col-sm-2 control-label">Hobby</label> <div class="col-sm-10"> <input type="text" class="form-control" id="ipt_hobby" placeholder="爱好" name="hobby" value="{{ edit_user_data.hobby }}" > </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-success">提交修改</button> </div> </div> </form> </div> </div> </div> </body> </html>
- add_user.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="/static_file/js/jquery.min.js"></script> <script src="/static_file/js/bootstrap.min.js"></script> <link rel="stylesheet" href="/static_file/css/bootstrap.css"> </head> <body> <div class="container"> <div class="row"> <div class="col-md-8 col-md-offset-2"> <h1 class="text-center">添加</h1> <br> <form class="form-horizontal" action="" method="post"> {% csrf_token %} <div class="form-group"> <label for="ipt_uname" class="col-sm-2 control-label">Uname</label> <div class="col-sm-10"> <input type="text" class="form-control" id="ipt_uname" placeholder="姓名" name="name"> </div> </div> <div class="form-group"> <label for="ipt_passwd" class="col-sm-2 control-label">Age</label> <div class="col-sm-10"> <input type="text" class="form-control" id="ipt_passwd" placeholder="年龄" name="password"> </div> </div> <div class="form-group"> <label for="ipt_hobby" class="col-sm-2 control-label">Hobby</label> <div class="col-sm-10"> <input type="text" class="form-control" id="ipt_hobby" placeholder="爱好" name="hobby"> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-success">新增数据</button> </div> </div> </form> </div> </div> </div> </body> </html>
五、ORM创建表关系
表与表之间的关系
- 一对多
- 多对多
- 一对一
- 没有关系
'''
以图书库为例:
有 图书表、出版社表、作者表、作者详情表。
'''
1.其中,图书和出版社是一对多关系,外键字段建在多的那一方,也就是book表
# 多个图书可以在同一家出版社出版,而同一本书因为版权不能再不同出版社出版,所以是“一对多”的关系。
2.图书和作者是多对多的关系,需要创建第三张表来专门存储,该表用来存储图书与作者的对应关系,类似于django路由。
3.作者与作者详情表是一对一
4.作者和出版社,没有关系,所以不需要建立表关系。
代码示例:
一、图书表与出版社表建立一对多关系,与作者表建立多对多关系
# 图书表
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8,decimal_places=2)
# 总共八位 小数点后面占两位
"""图书和出版社是一对多,并且书是多的一方,所以外键字段放在书表里面。"""
publish = models.ForeignKey(to='Publish') # 默认是与出版社表的主键字段做外键关联
"""图书和作者是多对多的关系,外键字段建在任意一方均可,但是推荐建在查询频率较高的一方。
authors是一个虚拟字段,主要是用来告诉orm,书籍表和作者表是多对多关系,让orm自动帮你创建第三张关系表。
第三张关系表为 应用名_book_authors
"""
authors = models.ManyToManyField(to='Author')
# 出版社表
class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
-
如果字段对应的是ForeignKey,那么orm会自动在字段的后面加_id,也就是book表中会多一个字段,名叫publish_id。
默认强制加的,如果字段名叫做publish_id,那么还是会加上_id后缀,就变成了publish_id_id
所以,后面在定义ForeignKey的时候就不要自己加_id
二、作者与作者详情表建立一对一关系
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
"""
作者与作者详情是一对一的关系,外键字段建在任意一方都可以,但是推荐建在查询频率较高的表中。
"""
author_detail = models.OneToOneField(to='AuthorDetail')
class AuthorDetail(models.Model):
phone = models.BigIntegerField() # 或者直接字符类型
addr = models.CharField(max_length=32)
- 注:如果字段对应的是OneToOneField,那么会和ForeignKey一样,会自动在末尾添加_id后缀。
总结:
-
ORM中如何定义三种关系
''' 一对多 ''' models.ForeignKey(to='表名(类)') ''' 多对多 ''' res = models.ManyToManyField(to='表名(类)') # res为个虚拟字段,主要是用来告诉orm是多对多关系,需要它创建第三张关系表 ''' 一对一 ''' models.OneToOneField(to='表名(类)') # 示例: publish = models.ForeignKey(to='Publish') # 一对多 authors = models.ManyToManyField(to='Author') # 多对多 author_detail = models.OneToOneField(to='AuthorDetail') # 一对一