模型进阶:
Mysql配置:
1.安装mysql
2安装MySQL驱动,使⽤mysqlclient
pip install mysqlclient
pip install -i https://pypi.douban.com/simple mysqlclient
Linux Ubuntu下需要先安装:apt install libmysqld-dev
再安装: apt install libmysqld-dev
3.在Django中配置和使⽤mysql数据库
使⽤mysql数据库,settings中配置如下:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mydb',
'USER': 'root', 'PASSWORD': '123456',
'HOST': '127.0.0.1',
'PORT': '3306',
}
}
迁移到mysql中。
查看:
mysql和sqlite只有配置是不一样的,其他的语句是类似的。
管理关系:
多个模块关联关联分类
- ·ForeignKey:⼀对多,将字段定义在多的端中,外键
- ·ManyToManyField:多对多,将字段定义在两端的任意⼀端中
- ·OneToOneField:⼀对⼀,将字段定义在任意⼀端中
⼀对多关系,举例说明:
⼀个班级可以有多个学⽣, ⼀个学⽣只能属于⼀个班级
多对多就是两个一对多。
class Grade(models.Model):
name = models.CharField(max_length=20)
class Student(models.Model):
name = models.CharField(max_length=20)
grade = models.ForeignKey(Grade, on_delete=)
对象的使⽤:
正向(在Student这边,有grade属性的这⼀边): 获取学⽣所在班级(对象): stu.grade
获取学⽣所在班级的属性: stu.grade.name
反向(在Grade这边):
获取班级的所有学⽣(获取Manager对象):grade.student_set
获取班级的所有学⽣(获取QuerySet查询集): grade.student_set.all()
filter(),get()等操作中的使⽤:
正向(在Student这边,有grade属性的这⼀边):
Student.objects.filter(属性 name='1')
如:Student.objects.filter(grade name='1') 反向(在Grade这边):
Grade.objects.filter(类名⼩写 id=7)
如:Grade.objects.filter(student id=7)
连表结构:
⼀对多:models.ForeignKey(其他表)
多对多:models.ManyToManyField(其他表)
⼀对⼀:models.OneToOneField(其他表) 应⽤场景:
⼀对多:当⼀张表中创建⼀⾏数据时,有⼀个单选的下拉框(可以被重复选择)
例如:创建⽤户信息时候,需要选择⼀个⽤户类型【普通⽤户】【⾦牌⽤户】【铂⾦⽤户】
多对多:在某表中创建⼀⾏数据时,有⼀个可以多选的下拉框。(猫眼App, 淘票票,格拉瓦电影) 例如:创建⽤户信息,需要为⽤户指定多个爱好。
⼀对⼀:在某表中创建⼀⾏数据时,有⼀个单选的下拉框(下拉框中的内容被⽤过⼀次就消失了)
例如:有个身份证表,有个person表。每个⼈只能有⼀张身份证,⼀张身份证也只能对应⼀个⼈,这就是⼀对⼀关系。
一对多:
py
from django.contrib import admin
from django.urls import path
from OnetoMany import views as one2many_view
urlpatterns = [
# 1对多
path('one2many/adduser/', one2many_view.add_user),
path('one2many/deluser/', one2many_view.del_user),
path('one2many/updateuser/', one2many_view.update_user),
path('one2many/getuser/', one2many_view.get_user),
path("admin/", admin.site.urls),
]
添加数据:
一对多下 的views.py 提供接口层。
py
from django.shortcuts import render, HttpResponse
from OnetoMany.models import *
# 一对多关系
# 添加数据
def add_user(request):
# 给UserType添加数据
# user_types = ['青铜', '白银', '黄金', '钻石', '大师', '王者']
# for name in user_types:
# UserType.objects.create(name=name)
# # 给User添加数据
for i in range(11, 30):
# User.objects.create(name=f'张三-{i}', age=i,
# user_type_id=i % 6 + 1)
# user_type 需要填入的是对象,而不是id
User.objects.create(name=f'李四-{i}', age=100 + i,
user_type=UserType.objects.get(pk=i % 6 + 1)) # 拿到映射后的结果
return HttpResponse('添加成功!')
删除数据:
py
from django.shortcuts import render, HttpResponse
from OnetoMany.models import *
# 删除数据
def del_user(request):
# 删除User数据
# User.objects.filter(id=6).delete()
# 删除UserType数据
UserType.objects.filter(id=3).delete()
return HttpResponse('删除成功!')
py
from django.db import models
# 1对多 = 1:N
# 用户类型 : 用户 = 1:N
# 一种用户类型:可以有多个用户
# 一个用户:只属于一个用户类型
# 用户类型
class UserType(models.Model):
name = models.CharField(max_length=30)
# 一个用户类型可以有多个用户
# on_delete 删除外键对另一个外键的影响
# 用户
class User(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField(default=18)
# 外键
user_type = models.ForeignKey(UserType, on_delete=models.CASCADE) # 级联删除
# user_type = models.ForeignKey(UserType, on_delete=models.PROTECT) # 保护模式 有关联的 则阻止删除
# user_type = models.ForeignKey(UserType, on_delete=models.SET_NULL, null=True) # 置空模式
# user_type = models.ForeignKey(UserType, on_delete=models.SET_DEFAULT, default=1) # 置默认值
# user_type = models.ForeignKey(UserType, on_delete=models.DO_NOTHING) # 报错FOREIGN KEY constraint failed
# # related_name: 关联名称, 设置反向查找的名称,原本使用user_set改为users
# user_type = models.ForeignKey(UserType, on_delete=models.PROTECT,
# related_name='users', # 建议使用
# )
# on_delete参数主要有以下几个可选值:
# models.CASCADE 默认值(Django1.11),表示级联删除,即删除UserType时,相关联的User也会被删除。
# models.PROTECT 保护模式, 阻止级联删除。
# models.SET_NULL 置空模式,设为null,null=True参数必须具备
# models.SET_DEFAULT 置默认值 设为默认值,default参数必须具备
# models.SET() 删除的时候重新动态指向一个实体访问对应元素,可传函数
# models.DO_NOTHING 什么也不做。
# 注意: 修改on_delete参数之后需要重新同步数据库,如果使用
修改数据:
py
# 修改数据
def update_user(request):
# 修改UserType
# 没有级联操作 因为关联的是id字段 而不是值,所以修改值没有任何影响
# UserType.objects.filter(id=1).update(name='钻石')
# 修改User
User.objects.filter(id=2).update(age=1000)
return HttpResponse('修改成功!')
查询数据:
py
from django.db import models
# 用户类型
class UserType(models.Model):
name = models.CharField(max_length=30)
# 一个用户类型可以有多个用户
# on_delete 删除外键对另一个外键的影响
# 用户
class User(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField(default=18)
# 外键
# # related_name: 关联名称, 设置反向查找的名称,原本使用user_set改为users
user_type = models.ForeignKey(UserType, on_delete=models.PROTECT,
related_name='users', # 建议使用
)
py
# 查询数据
def get_user(request):
# 正向查询:从User表去查找UserType 因为设置了外键
user = User.objects.get(id=2)
# print(user.name, user.age, user.user_type, user.user_type_id)
# print(user.user_type.name, user.user_type.id) # User所属UserType的所有数据
# 张三 - 12 1000 UserType object(1) 1
# 青铜 1
# 反向查询:
utype = UserType.objects.get(pk=1)
print(utype.id, utype.name) # UserType自己的属性
# 1 青铜
# user_set: 内部自动会生成的属性,可以让你反向查询到所有User集合
# print(type(utype.user_set)) # RelatedManager 关联的管理器对象
# # <class 'django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager.<locals>.RelatedManager'>
# print(utype.user_set.all()) # 查询集 QuerySet
# # <QuerySet [<User: User object (2)>, <User: User object (8)>, <User: User object (14)>, <User: User object (21)>, <User: User object (2
# # 7)>, <User: User object (33)>]>
# print('-' * 60)
# 在filter中还可以这么用
# 比如:查找用户类型名称为'白银'的所有用户
# 相当于关联的就是一个对象
# users = User.objects.filter(user_type=UserType.objects.get(name='白银')) # 传入UserType对象
users = User.objects.filter(user_type_id=2) # 传入user_type_id
users = User.objects.filter(user_type__name='白银') # 传入UserType对象的name属性作为条件
print(users)
print('-' * 60)
#
# # related_name:关联名称
utype = UserType.objects.get(pk=1)
# # print(utype.user_set.all()) # 报错,使用了related_name就不可以在使用带_set的属性
print(utype.users.all())
return HttpResponse('查询成功!')
多对多:
多对多关系
针对多对多关系django会⾃动创建第三张表。也可以通过through参数指定第三张表。
创建模型:
py
from django.db import models
# 电影
class Movie(models.Model):
name = models.CharField(max_length=100)
duration = models.IntegerField(default=90)
# 用户
class User(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField(default=18)
# 多对多关系
movies = models.ManyToManyField(Movie)
模型迁移到数据库:
py
from django.contrib import admin
from django.urls import path
from OnetoMany import views as one2many_view
from Manytomany import views as many2many_view
urlpatterns = [
# 1对多
path('one2many/adduser/', one2many_view.add_user),
path('one2many/deluser/', one2many_view.del_user),
path('one2many/updateuser/', one2many_view.update_user),
path('one2many/getuser/', one2many_view.get_user),
# many2many
path('many2many/add/', many2many_view.add),
path('many2many/delete/', many2many_view.delete),
path('many2many/get/', many2many_view.get_user_movie),
path("admin/", admin.site.urls),
]
删除数据:
py
# 删除数据
def delete(request):
# 删除User
# User.objects.filter(id=9).delete()
# 删除Movie
# Movie.objects.filter(id=9).delete()
# 删除中间表
user = User.objects.get(name='张三1')
user.movies.filter(name='阿凡达3').delete()
return HttpResponse('删除成功!')
查询操作:
py
# 查询数据
def get_user_movie(request):
# 获取用户收藏的所有电影
user = User.objects.get(id=1)
print(user.movies.all())
# 获取电影被哪些用户收藏了
# 反向则需要使用 模型名称_set
movie = Movie.objects.get(id=4)
print(movie.user_set.all())
return HttpResponse('查询成功')
⽤户和组是典型的多对多关系:
class Group(models.Model):
name = models.CharField(max_length=20)
def str (self):
return self.name
class User(models.Model):
name = models.CharField(max_length=64)
password = models.CharField(max_length=64)
groups = models.ManyToManyField(Group)
def str (self):
return self.name
操作:增:
先分别创建user和group, 再使⽤add关联
u = User(name='aa', password='123')
u.save()
g = Group(name='g5')
g.save()
通过Manager对象使⽤add()⽅法
u.groups.add(g) 或
g.user_set.add(u)
删:
和⼀对多类似,删除user或group会级联删除user_groups表中的关联数据改:
和⼀对多类似,只修改当前表查:
正向:
查询id=2的⽤户所在的所有组group
u = User.objects.get(id=2) u.groups.all()
反向:
查询id=1的组中包含的所有⽤户
g = Group.objects.get(id=1)
g.user_set.all()
一对一:
⼀对⼀不是数据库的⼀个连表操作,⽽是Django独有的⼀个连表操作。⼀对⼀关系相当于是特殊的⼀对多关系,只是相当于加了unique=True。
⼀个⼈只能有⼀张身份证,⼀张身份证对应⼀个⼈,是⼀个典型的⼀对⼀关系。
我们在创建一个App来对一对一模型进行演练:
写法一:
django-admin startapp Onetoone
写法二:
python manage.py startapp Onetoone
上面两种写法都可以实现创建app。
py
from django.db import models
# 身份证
class IDCard(models.Model):
idcard_num = models.CharField(max_length=18, unique=True)
address = models.CharField(max_length=200)
# 用户
class User(models.Model):
name = models.CharField(max_length=30, unique=True) # 姓名唯一
age = models.IntegerField(default=18)
sex = models.BooleanField(default=True)
# 一对一关系
# 建立映射关系
idcard = models.OneToOneField(IDCard, on_delete=models.PROTECT)
py
from django.shortcuts import render, HttpResponse
from Onetoone.models import *
# 一对一
# 增删改:和一对多是类似的
# 查询
def get(request):
# 查找某用户的身份证信息
user = User.objects.get(pk=1)
print(user.idcard) # 得到的是一个对象,不是查询集
print(user.idcard.idcard_num, user.idcard.address)
# 查找身份证对应的用户
idcard = IDCard.objects.get(pk=1)
print(idcard.user) # 对象
print(idcard.user.name, idcard.user.age, idcard.user.sex)
return HttpResponse('查询成功!')
总结
在这篇博客中,我们探索了Django模型的进阶主题,重点关注了配置MySQL数据库、模型惯例以及不同表之间的关系,包括一对一、一对多和多对多关系。通过这些讲解,我们深入了解了如何在Django中使用MySQL数据库,并利用模型惯例简化开发过程。
首先,我们介绍了如何配置MySQL数据库作为Django项目的后端存储。通过正确配置数据库连接信息,我们能够与MySQL建立连接,并使用Django的ORM(对象关系映射)功能进行数据操作。
接着,我们研究了Django的模型惯例,这是一种约定俗成的规则,用于定义模型类的结构和字段。了解这些惯例有助于提高代码的可读性和可维护性,并遵循行业最佳实践。
然后,我们深入研究了不同表之间的关系。一对一关系表示两个表之间的唯一对应关系,一对多关系表示一个表中的记录可以关联到另一个表中的多个记录,而多对多关系表示两个表之间的多对多关系,需要通过中间表来进行关联。
通过具体的示例和代码片段,我们详细讲解了这些关系的定义、使用和查询方法。这些知识对于设计复杂的数据库结构和构建功能强大的应用程序至关重要。
总而言之,本文提供了关于Django模型进阶的全面指南。从配置MySQL数据库到模型惯例和不同表之间的关系,我们希望读者可以通过这些讲解提升对Django的理解和应用能力,从而构建出高效、可靠的Web应用程序。