数据库
Django也是支持ORM按照面向对象的方法来操作数据库的,关于ORM的介绍请参考博文(https://blog.csdn.net/nie7342/article/details/101292571)
Django数据库配置和迁移:
1.手动创建MySQL数据库
create database db_django01 charset=utf8;
2.在settings中配置使用数据库
DATABASES = {
'default': {
# 配置使用mysql
'ENGINE': 'django.db.backends.mysql', # 数据库产品
'HOST': "localhost", # 数据库ip
'PORT': 3306, # 数据库端口
'USER': "root", # 用户名
'PASSWORD': "mysql", # 密码
'NAME': "db_django01", # 数据库名
}
}
3.在虚拟环境中安装MySQL驱动
pip install pymysql
4.在项目包init下初始化MySQL
import pymysql
pymysql.install_as_MySQLdb()
5.生成迁移文件
python manage.py makemigrations
6.生成数据库表
python manage.py migrate
7.建立数据库模型
class Department(models.Model):
"""部门类"""
# 部门名称:字符串类型(必须要指定最大长度)
name = models.CharField(max_length=20)
create_date = models.DateField(auto_now_add=True)
# 逻辑删除标识:标识部门是否删除
is_delete = models.BooleanField(default=False)
def __str__(self):
return self.name
class Meta:
# 指定表名
db_table = 'department'
class Employee(models.Model):
"""员工类"""
choices_gender = (
(0, '男'),
(1, '女'),
)
name = models.CharField(max_length=20)
age = models.IntegerField()
gender = models.IntegerField(default=0, choices=choices_gender)
# 工资:浮点类型(必须要指定两个选项) 999999.99
salary = models.DecimalField(max_digits=8, decimal_places=2)
# 备注信息: 可以为空
comment = models.CharField(max_length=300, null=True, blank=True)
# 员工入职时间
hire_date = models.DateField(auto_now_add=True)
# 一对多的外键:员工所属部门 department_id
department = models.ForeignKey('Department', on_delete=models.CASCADE)
def __str__(self):
return self.name
class Meta:
# 指定表名
db_table = 'employee'
CharField:表示字符串,必须指明最大长度
DateField:表示日期类型,属性auto_now_add表示对象第一次被创建时自动保存创建时间
choices:相当于枚举,配合default使用
DecimalField:十进制浮点数,必须制定总位数和小数位数
null和blank都表示是否允许为空,null = True表示允许输入为空,null是数据库范畴的概念,blank是表单验证范畴的
on_delete=models.CASCADE,当关联的外键department删除时候对应的employee数据也会删除,如果不想删除关联数据,可设置on_delete为 PROTECT
常见的数据库字段类型和选项
常用的字段选项
模型管理器
每个模型类默认都有一个叫object的属性,我们称之为模型管理器,通过object属性可以实现对数据库的相关操作
增
对应有两种方法,模型类对象.save()和模型类.objects.create(属性1=值1,属性2=值2, …),个人比较倾向于第二种用法
Department.objects.create(
name='后勤部',
create_date='2017-1-1'
)
删:两种方法:模型类对象.delete()和模型类.filter(条件).delete()
Department.objects.filter(id=1).delete()
改:两种方法:模型类对象.save()和模型类.filter(条件).update(属性1=值1,属性2=值2, …)
Department.objects.filter(id=1).update(name='人事部')
查:
条件查询:exact
Employee.object.filter(id = 1)
模糊查询: contains / endswith / startswith
Employee.object.filter(name__contains = '马')
Employee.objects.filter(name__endswith='军')
空查询:isnull
Employee.objects.filter(comment__isnull=False)
范围查询:in
Employee.objects.filter(id__in=[1,3,5])
比较查询:gt/gte/lt/lte
Employee.objects.filter(age__gte=30)
日期查询:year
Employee.objects.filter(hire_date__year=2019)
Employee.objects.filter(hire_date__gte='2019-1-1')
F对象:
之前查询的都是对象属性与常量之间的比较,如果是查询对象属性与属性之间的比较呢?比如查询查询语文分数大于数学分数的学生。这就是F对象,即查询属性之间的比较
Employee.object.filter(age__gt = F('id') * 4)#查询年龄大于4倍id的员工
Q对象:对查询条件进行与或非的逻辑运算,即一次性加入多个条件进行查询。并且:& 或者:| 取反:~
Employee.objetc.filter(Q(age__gt = 30) & Q(id__gt = 3))#查询年龄>30并且id<3的员工
Employee.objects.filter(Q(id__gt=3) | Q(age__gt=30))
Employee.objects.filter(~Q(id=3))
排序:对查询结果集进行排序,升序: 模型类.objects.order_by(‘属性名’)降序: 模型类.objects.order_by(’-属性名’)
Employee.objects.filter(id__gt=8).order_by('-age')#id大于8且按年龄从大到小排序显示
aggregate方法:对多行查询结果集中的一列进行操作,使用方法:模型类.objects.aggregate(聚合类(‘属性名’)),
常用聚合类有:Sum, Count, Max, Min, Avg等
返回值是一个字典, 格式: {‘属性名__聚合函数’: 值}
Employee.objects.aggregate(Avg('salary'))#查询平均工资
Employee.objects.count()#统计所有的员工数
Employee.objects.filter(id__gt=3).count()#统计id>3的员工数
关联查询:
由 一类对象 查询 多类对象: 一类对象.多类名小写_set.all()
由 多类对象 查询 一类对象: 多类对象.关联属性
d = Department.objects.get(name=‘研发部’)
d.employee_set.all() # 一查多
e = Employee.objects.get(name='码云')
e.department # 多查一
查询集:
- 当调用模型管理器的 all, filter, exclude, order_by等方法时,返回的是一个 QuerySet 对象,表示从数据库查询到的数据集合
- QuerySet 支持 下标 和 切片 操作,query_set[0]:取出查询集中的第一条数据,不存在会抛IndexError异常,query_set[0:2]:切片操作得到另一个新的QuerySet
- 惰性:创建查询集时不会访问数据库,操作查询集中的数据时才会访问
- 当遍历(迭代)访问查询集 所有数据,会缓存查询集所有数据,当再次操作该查询集中的数据时,将会使用缓存,如果只是访问查询集 部分数据(下标或切片)不会缓存
query_set = Department.objects.all() [dep.name for dep in query_set] #使用缓存,不再查数据库 [dep.name for dep in query_set]
自定义模型管理器:
比如有如下场景: 调用 Department.objects.all()时,返回的是 is_delete 等于False的部门,我们可以返回all之后再接着逻辑判断也可以自定义all方法,自定义后模型管理器后, Django 将不再自动生成默认的 objects,我个人的习惯是很少自定义模型管理器的。
class DepartmentManager(Manager):
#自定义模型管理器
def all(self):
"""重写all方法:只返回没有删除的部门"""
return super().all().filter(is_delete=False)
def create_dep(self, name, create_date):
"""封装新增部门的方法,方便调用"""
dep = Department()
dep.name = name
dep.create_date = create_date
dep.save()
return dep
class Department(models.Model):
"""部门类"""
...
# 使用自定义模型管理器,生成object对象
objects = DepartmentManager()
admin站点管理
1.使用admin站点管理后台
首先创建后端管理员
python manage.py createsuperuser
2.注册模型,将需要管理的模块site进来
# users/admin.py:
from app01.models import Department, Employee
# 注册Model类
admin.site.register(Department)
admin.site.register(Employee)
3.启动服务器,访问 http://127.0.0.1:8000/admin 地址,进入管理后台
4.自定义列表页展示:
class DepartmentAdmin(admin.ModelAdmin):
class Meta:
...
verbose_name = '部门'
verbose_name_plural = verbose_name # 去掉复数的s
# 指定要显示的属性
list_display = ["id", "name"]
list_per_page = 5 #指定每页显示多少条数据
actions_on_top = True # 显示顶部操作栏
actions_on_bottom = True # 显示底部操作栏
list_filter = ['gender', 'department'] #显示过滤器栏
search_fields = ['name']#显示搜索栏
fields = ['name', "age", "department"]#自定义可编辑字段
fieldsets = (
('基本', {'fields': ('name', 'age', 'gender')}),
('高级', {'fields': ('comment', 'department')}),
)#字段分组显示
class EmployeeAdmin(admin.ModelAdmin):
class Meta:
...
verbose_name = '员工'
verbose_name_plural = verbose_name # 去掉复数的s
# 指定要显示的属性
list_display = ["id", "name", "age", "gender", "comment", "department"]
# 参数2: 注册Admin类
admin.site.register(Department, DepartmentAdmin)
admin.site.register(Employee, EmployeeAdmin)
django管理后台可以实现对关联数据的编辑,例如:在编辑部门时,可以显示出该部门关联的所有员工对象,并进行编辑; 显示时,有如下两种显示方式:
子类 TabularInline: 以表格的方式嵌入显示
子类 StackedInline: 以栈的方式嵌入显示
class DepartmentStackedInline(admin.StackedInline):
model = Employee # 关联对象类型
class DepartmentTabularInline(admin.TabularInline):
model = Employee # 关联对象类型
class DepartmentAdmin(admin.ModelAdmin):
...
# inlines = [DepartmentTabularInline] # 栈的方式显示
inlines = [DepartmentStackedInline] # 表格样式显示
同时我们还可以设置管理页面的标题,标语等信息
admin.site.site_title 设置页面标题
admin.site.site_header 设置网站页头
admin.site.index_title 设置首页标语
最后再介绍一个常用的功能:上传图片
1.使用Admin站点保存图片,需要安装Python的图片操作包
pip install Pillow
2.默认情况下,Django会将上传的图片保存在本地服务器上,可以指定具体保存在哪个目录下:
MEDIA_ROOT=os.path.join(BASE_DIR,"media")
增加测试类
class TestUser(models.Model):
name = models.CharField(max_length=20)
# 用户头像
avatar = models.ImageField(upload_to='users', null=True)
#upload_to 指定该字段的图片保存在MEDIA_ROOT目录中的哪个子目录下
迁移生成数据库
**
python manage.py makemigrations
python manage.py migrate
**