SUMMER
Django视图层的主要用来处理对应url的请求并且返回响应数据,在这个请求-响应的过程中大致涉及到两点,第一就是视图层会和模型层(数据相关)进行交互,对数据进行增删改查,第二是视图层需要将某些数据传递给前端HTML页面。本文主要介绍第一部分视图层如何与数据库进行交互。
模型层功能介绍

django模型层的主要功能就是与数据库进行交互,使用ORM(对象关系映射)方便的实现数据的增删改查操作,django自带了一个数据库sqlite3,但是该数据库对日期格式好像不是非常敏感,处理的时候容易出错,因此通常在django框架中使用其他数据库,比如MySQL。
django连接MySQL

在实际开发中通常不使用django自带的sqlite3,而是换成MySQL或者其他关系型数据库,具体配置方式如下:
第一步需要修改django的配置文件settings.py中的数据库DATABASES配置:
# 修改前DATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3','NAME': os.path.join(BASE_DIR, 'db.sqlite3'),}}# 修改后DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql','NAME': 'practice', // MySQL库的名字'USER':'root', // MySQL用户名'PASSWORD':'1026', // MySQL密码'HOST':'127.0.0.1', // 数据的地址'PORT':3306,'CHARSET':'utf8',}}
第二步需要进行代码声明,在与项目同名的目录下的__init__.py文件中书写下述代码,意思是告诉django不要使用默认的mysqldb改为使用pymysql。
# first_django/fist_django/__init__.pyimport pymysqlpymysql.install_as_MySQLdb()
django ORM

在python如何操作mysql的文章中提到可以通过在pymysql模块执行SQL语句从而操作数据库,但是写在Python中书写SQL语句总觉得怪怪的...
django ORM(对象关系映射)的作用就是可以通过python面向对象的代码快捷的操作数据库,不过也有缺点就是封装程度太高,有时候SQL语句的效率偏低。既然ORM是对象关系映射,具体如何映射的,请看下图:

django ORM操作数据库

第一步去应用下的models.py下创建类,对应到MySQL中的表,类必须继承models.Model,每个应用用到什么表就创建什么类。
from django.db import models# Create your models here.class Info(models.Model):# id int primary key auto incrementid = models.AutoField(primary_key=True,verbose_name=id)# username varchar(32)username = models.CharField(max_length=32,verbose_name=username)# password intpassword = models.IntegerField(verbose_name='password')
但是此时在数据库中并未产生任何数据,如果想要在数据库中产生对应的表就必须执行数据库迁移命令,并且只要修改了models.py中和数据库相关的代码就必须执行数据库迁移命令,数据库迁移命令有两条:
python manage.py makemigrations // 将数据记录在小本本上(migrations文件夹中会产生一个文件)python manage.py migrate // 将操作真正的同步到数据库中

django ORM常用字段和字段参数

首先看一下常用的字段:
AutoField: int自增整形字段,一个model不能有两个该字段primary_key:是否自增,设置为True字段是主键列IntegerField: 整数类型,不需要额外的其他参数CharField: 字符串类型必须提供max_length参数表示接收的字符串的最大长度TextField: 大段文本类型DateTimeField:时间类型,年月日时分秒都显示auto_now:为True时修改某条记录时的最新时间auto_now_add:为True时新增数据会自动保存当前时间,修改数据不会DateField:时间类型,只显示年月日auto_now:为True时修改某条记录时的最新时间auto_now_add:为True时新增数据会自动保存当前时间,修改数据不会EmailField: 邮箱格式的字符串数据,在存数据时会校验是否是邮箱格式。BoolenField:存储布尔值,只有两种情况ImageField: 图片类型upload_to:文件图片上传只服务器端的路径width_field: 限制图片的宽度height_field:限制图片的高度FieldField: 文件类型upload_to:文件上传只服务器端的路径
下面是字段中常用的参数:
null: 表示数据是否非空,默认是False,推荐使用默认即可blank:默认是False,验证表单数据是否为空,推荐设为Truedefault:数据库字段设置默认值unique:表示数据是否唯一to: 字段与哪张表有外键关系on_delete:当等于models.CASCADE是表示级联更新级联删除当等于models.DO_NOTHING时表示不级联更新,此时还需要另一个参数db_constraintdb_constraint: 当等于True时表示斩断有关联表之间的`联系`,有关联的表只存在逻辑上的外键关系,推荐使用db_index: 表示字段是否是索引字段db_column: 字段在数据库中的名字,如果不设置,数据库中的字段就是模型中属性的名字choices: 类似于MySQL中的枚举enum,具体使用方式如下gender_choice = ((0, 'male'),(1, 'female'),(2, 'others'))gender = models.IntegerField(choices=gender_choice, default=0) # 表示gender字段的值只有三种0,1,2, 默认是0verbose_name:django admin中显示的表字段的名称help_text:类似于备注
另外对于一些模型级别的配置即表级别的配置可以在模型中定义一个Meta类,在这个类中添加一些属性控制表的其他属性,比如联合索引、指定表名而不是使用模型的类型:
class User(models.Model):id = models.AutoField(primary_key=True, verbose_name='主键')name = models.CharField(max_length=10, verbose_name='用户名')age = models.IntegerField(verbose_name='年龄')class Meta:db_table = '用户表' # 指定表名而不是使用类名Userindex_together = [(name, age)] # name age字段组成联合索引不一定唯一unique_together = [(name,age)] # name age组成联合唯一索引

django ORM操作表数据 --- 单表增删改查

搭建测试环境
在对数据进行操作时为了方便,不在视图函数中进行操作,而是在django的测试环境中进行操作,因此首先需要搭建测试环境,在django应用中有一个test.py是django提供的测试文件,当然也可以自己在应用下创建测试的py文件,搭建测试环境需要加载django项目的配置文件,只有加载了django的项目配置文件才能使用测试文件,在测试文件中写入下述代码测
试环境即搭建完成:if __name__ == '__main__':import osimport djangoos.environ.setdefault('DJANGO_SETTINGS_MODULE', 'first_django.settings') # 此行代码来自于manage.py-加载配置django.setup()# 在这下面写操作数据库的代码,注意缩进哦~
首先创建一张表,基于这张表进行增删改查的基本操作:
# models.pyfrom django.db import modelsclass User(models.Model):id = models.AutoField(primary_key=True) # 不写的话Django会自动创建,且列名为idusername = models.CharField(max_length=8, verbose_name='用户名')age = models.IntegerField(verbose_name='年龄')GENDER = ((0, 'male'),(1, 'female'),(2, 'others'))gender = models.IntegerField(choices=GENDER, verbose_name='性别')create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')alter_time = models.DateTimeField(auto_now=True, verbose_name='最后修改时间')def __str__(self):return self.username
千万不要忘记执行数据库迁移命令!
python manage.py makemigrationspython manage.py migrate
去数据库验证是否已经产生了新的表,表名是应用名_类名小写,发现已经创建好了:
mysql> use practice;Database changedmysql> show tables;+----------------------------+| Tables_in_practice |+----------------------------+| auth_group || auth_group_permissions || auth_permission || auth_user || auth_user_groups || auth_user_user_permissions || django_admin_log || django_content_type || django_migrations || django_session || first_user |+----------------------------+11 rows in set (0.00 sec)
数据基本增删改查
下面就可以在test.py中进行数据的增删改查了。需要提到一点,就是在写orm语句时,当使用主键字段当做查询条件时,无论主键字段名是什么都可以使用pk代替。
# test.pyif __name__ == '__main__':import osimport djangoos.environ.setdefault('DJANGO_SETTINGS_MODULE', 'first_django.settings')django.setup()from first import models# 增加数据,create用来增加数据user_info = {'username': 'python','age': 10,'gender': 0,}user_obj = models.User.objects.create(**user_info) # 返回User的对象# 也可以写成user_obj = models.User.objects.create(username='python', age=10, gender=0)print(user_obj)# 修改数据# 修改方式1,推荐使用此种方式alter_info = {'username': 'java'}edit_obj = models.User.objects.filter(pk=1).update(**alter_info)print(edit_obj)# 修改方式2这种方式不推荐使用,在字段特别多的时候效率会非常低# ①首先获取需要修改的对象,filter用来筛选数据得到的是一个类似列表的结构edit_obj = models.User.objects.filter(id=1).first() # .first()只要第一个数据# ②使用对象.属性的方式进行修改,edit_obj.username = alter_info['username']edit_obj.save() # 不要忘记保存# 删除数据# 批量删除res = models.User.objects.filter(username='python').delete()# 单一删除res = models.User.objects.filter(pk=1).first().delete()# 查询数据,filter的条件可以有多个,以逗号连接多个条件,表示and关系# 查询单条数据user_obj = models.User.objects.filter(username='java', age=5)print(user_obj) # <QuerySet [<User: java>]>得到queryset对象,支持索引取值但是不推荐,推荐使用first方法取值print(user_obj.first()) # java 获取对象# 查询所有数据user_objs = models.User.objects.all()print(user_objs) # <QuerySet [<User: java>, <User: python>]>
查看ORM语句对应的SQL
如果想要查看ORM语句对应的SQL语句的话,有两种方式:
# 方式一:queryset对象.query可以得到返回值是queryset对象的ORM语句对应的SQL语句user_objs = models.User.objects.all()print(user_objs.query)# 方式二:所有的SQL语句都可以查看,需要配置文件中进行配置,打印ORM语句返回值时会直接显示对应的SQL语句# 将下述代码配置到配置文件中即可LOGGING = {'version': 1,'disable_existing_loggers': False,'handlers': {'console':{'level':'DEBUG','class':'logging.StreamHandler',},},'loggers': {'django.db.backends': {'handlers': ['console'],'propagate': True,'level':'DEBUG',},}}
ORM语句其他方法
上面所有的增删改查操作都是单表操作,除了上述提到的方法之外,还需要介绍另外的一些方法,下述方法只有QuerySet对象可以调用。
last(): queryset对象中的最后一个对象values('username'):可以获取指定字段的数据,类似于select username, age from user;也可以不指定,返回结果是queryset对象,列表套字典的格式:<QuerySet [{'username': 'python'}, {'username': 'python'}, {'username': 'python'}, {'username': 'python'}]>value_list('username'):可以获取指定字段的数据,返回的结果是queryset对象,列表套元组,<QuerySet [('python',), ('python',), ('python',), ('python',)]>distinct():去重操作,去重一定要是一摸一样的数据,如果带有主键去重,肯定无法进行去重比如:models.User.objects.values('name','age').distinct()order_by():排序操作,默认是升序,在排序规则前加-就是降序models.User.objects.order_by('age')models.User.objects.order_by('-age')reverse():反转操作,反转的前提是数据已经排过序了,必须跟在order_by之后models.User.objects.order_by('name').reverse()count():统计数量res = models.User.objects.count()exclude():将某条数据排除在外res = models.User.objects.exclude(name='java')print(res)exists(): 判断某个数据是否存在,基本用不到,因为数据本身就自带布尔值,返回的是布尔值res = models.User.objects.filter(pk=2).exists()print(res)
查询数据 - 双下划綫
在查询数据的时候,很多时候筛选条件都不是=,还有很多筛选条件是>=,<=,<,>还有模糊查询、区间查询等,那么这些又如何进行查询呢?很多小伙伴觉得那就用>=,<=,<,>这些符号不行吗?这里明确的说明在django ORM的筛选条件中不支持直接写上述符号,而是使用神奇的双下划綫方法。双下划綫可以在filter()
中实现神奇的操作,灵活的实现数据的过滤查询,基本语法filter(字段名__方法),以下面的例子进行说明双下划綫的用法:
# 大于: __gtmodels.User.objects.filter(age__gt=3) # 过滤年龄 > 3的# 小于:__ltmodels.User.objdects.filter(age__lt=3) # 过滤年龄 < 3的# 大于等于:__gtemodels.User.objdects.filter(age__gte=3) # 过滤年龄 >=3 的# 小于等于:__ltemodels.User.objdects.filter(age__lte=3) # 过滤年龄 <=3 的# 区间过滤models.User.objects.filter(age__in[1, 2, 3]) # 年龄是其中之一的models.User.objects.filter(age_range=[1, 10]) # 年两在1-10之间的,包括首尾# 模糊查询models.User.objects.filter(name__contains='p') # 区分大小写名字包含p的models.User.objects.filter(name__icontains='p') # 不区分大小写,名字包含p的models.User.objects.filter(name__startswith='p') # 名字以p开头的models.User.objects.filter(name__endswith='a') # 名字以a结尾的# 时间查询models.User.objects.filter(register_time__year='2021') # 时间是2021年的models.User.objects.filter(register_time__month='7') # 时间是7月的models.User.objects.filter(register_time__day='21') # 时间是21日的
文章还没结束哦~

django模型层的知识稍微多一些,上面介绍了单表操作,多表操作留在下一篇文章中介绍吧,不然一篇文章的字数太多,吃不消呀~
小庄卖瓜

如果想要了解更多python知识,欢迎关注小庄微信公众号,我们一起学(zi)习(kua)吧~
往期推荐

+
+
+
+




