06-模型层1——单表操作
简介
MTV框架包含一个重要的部分就是ORM————对象关系映射(Object Relational Mapping),它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员的工作量,不需要面对因数据库变更而导致的无效劳动。
ORM是“对象-关系-映射”的简称(Object Relational Mapping)。
需要注意的是:
数据库必须提前创建好————ORM在数据库中进行表的操作。
ORM只能对表进行操作,也可以对表下面的记录进行操作,但是ORM不能对数据库进行操作,不能创建与删除数据库。
类对象--->sql--->pymysql--->mysql服务端--->磁盘,orm其实就是将类对象的语法翻译成sql语句的一个引擎,明白orm是什么了,剩下的就是怎么使用orm,怎么来写类对象关系语句。
还有一个sqlalchemy和他很像,但是django的orm没有独立出来让别人去使用,虽然功能比sqlalchemy更强大,但是别人用不了。
原生SQL与Django中的ORM对比:
sql中的表操作
#创建表:
CREATE TABLE employee(
id INT PRIMARY KEY auto_increment ,
name VARCHAR (20),
gender BIT default 1,
birthday DATA ,
department VARCHAR (20),
salary DECIMAL (8,2) unsigned,
);
#添加一条表纪录:
INSERT employee (name,gender,birthday,salary,department)
VALUES
("whw",1,"1992-12-12",8000,"IT");
#查询一条表纪录:
SELECT * FROM employee WHERE age=24;
#更新一条表纪录:
UPDATE employee SET birthday="1991-10-24" WHERE id=1;
#删除一条表纪录:
DELETE FROM employee WHERE name="whw";
Django的ORM操作
#创建表
class Employee(models.Model):
id=models.AutoField(primary_key=True)
name=models.CharField(max_length=32)
gender=models.BooleanField()
birthday=models.DateField()
department=models.CharField(max_length=32)
salary=models.DecimalField(max_digits=8,decimal_places=2)
#添加一条表纪录:
emp=Employee(name="whw",gender=True,birthday="1991-12-12",epartment="IT")
emp.save()
#查询一条表纪录:
Employee.objects.filter(age=24)
#更新一条表纪录:
Employee.objects.filter(id=1).update(birthday="1991-10-24")
#删除一条表纪录:
Employee.objects.filter(name="whw").delete()
单表操作
创建表的过程
先创建一个数据库 whw
create database whw;
创建Django项目及相关配置
创建Django项目
然后创建一个Django项目 whw_dj3_ORM,然后在这个项目中创建一个app名为book:
python manage.py startapp book
相关的配置
(1)确保配置文件中的INSTALLED_APPS中写入我们常见的book应用的名称:
#在全局的settings.py的INSTALLED_APPS中加入book:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
#前面是既有的,这个book是新加的
'book',
]
(2)然后在book应用中的models.py文件中加入下面代码(如果没有名字必须命名为models)
from django.db import models
# Create your models here.
#注意这个Book类必须继承models.Model
class Book(models.Model):
#AutoField为自增对象,括号里面的是限定条件
id = models.AutoField(primary_key=True)
#CharField为一个字符串,括号里面表示它的最大长度
title = models.CharField(max_length=32)
state = models.BooleanField()
#DateField是存日期的
pub_date =models.DateField()
#DecimalField是一个浮点型:max_digits为最大的位数,但是有两位是小数——111111.11
price = models.DecimalField(max_digits=8,decimal_places=2)
publish = models.CharField(max_length=32)
#打印这个类展示的是它的title
def __str__(self):
return self.title
#(3)更多字段与更多参数详见pythonbook~
(3)想要将模型转换为mysql数据库中的表,需要在全局的settings中配置:
需要注意的是在Navicat中创建数据库的时候这些参数都有设置的,而且下面的参数是连接本机的数据库
如果要连接远程数据库就需要远程数据库的ip 端口等信息了。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',#引擎,选mysql
'NAME':'day58',#要连接的数据库,连接前需要创建好
'USER':'root',#连接数据库的用户名
'PASSWORD':'123',#连接数据库的密码
'HOST':'127.0.0.1',#连接主机,默认本本机
'PORT':3306,#端口 默认3306
#Django中设置数据库的严格模式
'OPTIONS':{
'init_command':"set sql_mode='STRICT_TRANS_TABLES' ",
}
}
}
(4)如果此时直接启动项目会报错:no module named MySQLdb。这是因为django默认你导入的驱动是MySQLdb.
可是MySQLdb对于py3有很大问题,所以我们需要的驱动是PyMySQL所以,我们只需要找到全局项目名文件下的init.py,在里面写入:
import pymysql
pymysql.install_as_MySQLdb()
(5)还需要注意的一点是,如果我们用的是django2.0版本,然后python用的是3.4以上的版本,需要进行如下的操作:
A、在python与django的安装路径找到:C:\Users\dell\AppData\Local\Programs\Python\Python36\Lib\site-packages\django\db\backends\mysql
B、将里面的base.py文件中的
if version < (1, 3, 3):
raise ImproperlyConfigured("mysqlclient 1.3.3 or newer is required; you have %s" % Database.__version__)
这句话注释掉!!!
(6)最后通过两条数据库迁移命令即可在指定的数据库中创建表(在Terminal中敲这两行代码就行了):
python manage.py makemigrations
python manage.py migrate
(7)然后我们就可以在数据库中看到新建的表book_book(还有其他的表)了。
#注意其他的表其实是django的全局的那个settings文件中INSTALLED_APPS列表下面默认应用对应的表~如果不需要可以把它们注释掉(除了contenttypes)!
#因为contenttypes生成的表记录着哪个app建了什么表!
#把其他的应用注释掉的话~就不会生成那个应用对应的表了!注意注释contenttypes的话迁移的时候会报错!
#在创建好表后,如果遇到问题~想要“重新建表”~删掉单独的那个业务有关表没用,另外要把migrations文件夹中的0001_initial.py那个py文件删掉的话~注意还需要把contenttypes这个表里面的0001_initial的对应的数据条目删掉~——理解django在执行makemigrations与migrate的过程!
#创建好表后如果想修改表结构或者添加字段,执行完数据库迁移指令后会在migrations文件夹中生成0002_initial文件
(8-1)如果想打印orm转换过程中的sql,需要在settings中进行如下配置:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
(8-2)还有另外一种查看SQL语句的方式
from app01 import models
def add_book(request):
'''
添加表记录
:param request: http请求信息
:return:
'''
book_obj = models.Book(title='python',price=123,pub_date='2012-12-12',publish='人民出版社')
book_obj.save()
from django.db import connection #通过这种方式也能查看执行的sql语句
print(connection.queries)
return HttpResponse('ok')
数据的增删改查
1、准备工作
1.1 所有的操作都在视图函数中进行,所以现在全局的urls中加入index的路由:
from django.contrib import admin
from django.urls import path,re_path
from book import views
urlpatterns = [
path('admin/', admin.site.urls),
re_path('^index$',views.index)
]
1.2 应用book的views视图函数是这样的:
from django.shortcuts import render,HttpResponse
#注意这里需要引入models!
from book import models
# Create your views here.
def index(request):
#这里写函数的主体
return HttpResponse('OK')
以后所有的操作都在book应用的views.py文件下的index函数中进行进行
2、添加表记录
create方法的返回值book_obj就是插入book表中的python葵花宝典这本书籍纪录对象
增加数据建议用方式一!
2.1方式一:直接实例化一个类对象————注意objects有很多方法,create是用来创建表的
注意create方法可以返回一个对象~需要查的话就不需要再进行查操作了~直接调用create方法返回的对象进行查找就OK了!
使用方法:
#注意日期按照这个格式来!
book_obj=models.Book.objects.create(title='Python葵花宝典',state=True,price=100,publish='苹果出版社',pub_date='2015-12-13')
#打印title...
print(book_obj.title)
##注意create是有返回值的,create方法的返回值book_obj就是插入book表中的python葵花宝典这本书籍纪录对象
推荐使用方式一~
2.2方式二:
book_obj=Book(title="python葵花宝典",state=True,price=100,publish="苹果出版社",pub_date="2012-12-12")
book_obj.save()
2.3方式三:批量插入
book_list = []
for i in range(10):
bk_obj = models.Book(
name='chao%s'%i,
addr='北京%s'%i
)
book_list.append(bk_obj)
models.Book.objects.bulk_create(book_list) #批量插入,速度快
2.4方式四:update_or_create——有就更新,没有就创建
obj,created = models.UserToken.objects.update_or_create(
user=user, # 查找筛选条件
defaults={ # 添加或者更新的数据
"token":random_str,
}
)
说明:
1、第一个值obj为:新创建的model对象
2、第二个值created为:是否进行了新的数据的插入的操作,只是更新原始数据为false,新加入数据为true!
3、如果查询到多条数据,那么就会报错!因为源码里面用的是get方法!可以用异常处理!
3、查询表记录
查询的API
***前4个最重要,5--9比较容易,10中的三个方法比较难也非常重要!
***一定要知道每个方法的返回值是什么,以及每个方法是由谁来调用的
(1)all()
models.Book.objects来调用,返回的是QuerySet类型的对象——django自己定义的数据类型
将查询出来的查询出来的所有对象放在列表中
在models的Book类中写了__str__方法,且__str__返回的是title的值,所以后面会打印title
book_list = models.Book.objects.all()
print(book_list)
#遍历这个字典可以进行相应的取值操作
for i in book_list:
print(i.title,i.price)
#也可以进行索引操作
print(book_list[0].pub_date)
(2)first与last
返回值不是QuerySet对象,而是model对象,等价于book_list[0]
调用者是QuerySet对象
book_first = models.Book.objects.first()
print(book_first)
(3)filter方法
对应where语句
调用者objects,返回值是QuerySet对象
book_list2 = models.Book.objects.filter(price=100)
print(book_list2)
(3-1)可以跟first或者last方法
book_list2_last = models.Book.objects.filter(price=100).last()
print(book_list2_last.pubdate)
(3-2)可以带多个多虑条件
book_list2_more = models.Book.objects.filter(price=100,title='西游记')
print(book_list2_more)
(4)get方法
很像filter,但是,get方法有且只有一个查询结果是才有意义;如果有多个查询结果会报错!
返回值是一个model对象,利用objects调用!
book_get = models.Book.objects.get(title='西游记')
print(book_get)
(5)exclude方法
排除——得到的是个QuerySet对象,由objects调用,也可以用QuerySet对象调用
models调用:
book_exclude = models.Book.objects.exclude(title='西游记')
print(book_exclude)
QuerySet调用:
ret = models.Book.objects.filter(price=11).exclude(id=2)
print(ret)
(6)order_by排序
得到的是QuerySet对象,由objects调用
(6-1)默认升序
book_order_by_asc = models.Book.objects.order_by('title')
print('升序:',book_order_by_asc)
(6-2)降序排序
book_order_by_desc = models.Book.objects.order_by('-title')
print('降序:',book_order_by_desc)
(6-3)也可以利用两个字段排序:——第一个字段相等的时候再用第二个字段排序
book_order_by1 = models.Book.objects.order_by('title','price')
print('两个字段排序:',book_order_by1)
(7)reverse反转
可以在order_by的基础上加上reverse
book_reverse = models.Book.objects.order_by('title').reverse()
print('排序反转:',book_reverse)
(8)count计数
返回int类型的数据,调用者是QuerySet
count = models.Book.objects.all().count()
print('数据的总数:',(count,type(count)))
(9)exists检测是否存在记录
如果不加exists则表示取出来所有的值了,没必要取所有的值,这样效率不高;
加上exists相当于利用limit限制只取出来一条数据去判断有没有记录。
ret = models.Book.objects.all().exists()
if ret:
print('OK!有数据!')
重点:(10)values(field)、values_list(field)、distinct()
下面这三个十分重要
(10-1)values(*field)
查询所有书籍的名称:
得到的是一个QuerySet对象: <QuerySet [{'title': 'Python葵花宝典'}, {'title': 'Python葵花宝典1'}, {'title': '金瓶瓶'}]>
由QuerySet对象调用
但是列表中放的不是一个个的对象了,而是一个个的字典!
book_titles = models.Book.objects.all().values('title')
print('所有书籍的名称:',book_titles)
"""
values的工作原理:
现在将values中的参数改为为'title','price'(注意value与value_list中可以放两个参数)
temp = []
for obj in models.Book.objects.all()
temp.append(
'title':obj.title,
'price':obj.price
)
return temp
"""
(10-1-1)也可以利用操作字典的方法来操作结果:
book_title_1_title = book_titles[1].get('title')
print('第二个书籍的名字:',book_title_1_title)
(10-2)values_list(*field)方法
与value方法一样,调用者与返回值均是QuerySet对象
但是,value_list的结果是列表里面嵌套元组
book_values_list = models.Book.objects.all().values_list('title')
print(book_values_list)
(10-3)distinct方法
去重
price_distinct = models.Book.objects.all().values('price').distinct()
print('price去重:',price_distinct)
4、查询表记录之带双下划线的模糊查询
注意要用filter过滤
(1)查询价格大于100的:gt
gt_100 = models.Book.objects.filter(price__gt=100)
print('价格大于100的:',gt_100)
注意大于等于的话是gte:
gte_100 = models.Book.objects.filter(price__gte=100)
(2)小于:lt
lt_10000 = models.Book.objects.filter(price__lt=10000)
print('价格小于10000的:',lt_10000)
(3)大于100小于10000的:
gt_100_lt_10000 = models.Book.objects.filter(price__gt=100,price__lt=10000)
print('价格大于100小于10000的:',gt_100_lt_10000)
(4)价格包含[100,200,300]这几个的:
price_in = models.Book.objects.filter(price__in=[100,200,300])
print('价格包含:',price_in)
(5)title以“西”字开头的数据:
title_starts_xi = models.Book.objects.filter(title__startswith='西')
print('title以西字开头:',title_starts_xi)
(6)包含——contains
title_contains = models.Book.objects.filter(title__contains='p')
print('title包含p的:',title_contains)
(6-1)忽略大小写的包含——icontains
title_icontains = models.Book.objects.filter(title__icontains='p')
print('title包含p或者P的:',title_icontains)
(7)在一个范围之内:range
price_range = models.Book.objects.filter(price__range=[100,10000])
print('价格在一个范围之内:',price_range)
(8)关于日期的模糊查询
(8-1)过滤一下出版日期是2014年的数据
###注意只有date类型的字段才有__year
###想查找月份就用__month就可以了
pub_date_2014 = models.Book.objects.filter(pub_date__year=2014)
print('2014出版的数据:',pub_date_2014)
注意的问题:
#找2012年的所有书籍
all_books = models.Book.objects.filter(pub_date__year=2012)
#找大于2012年的所有书籍
all_books = models.Book.objects.filter(pub_date__year__gt=2012)
#找2019年月份的所有书籍,如果明明有结果,你却查不出结果,是因为mysql数据库的时区和咱们django的时区不同导致的,
#你需要做的就是将django中的settings配置文件里面的USE_TZ = True改为False,就可以查到结果了,
#以后这个值就改为False,而且就是因为我们用的mysql数据库才会有这个问题,其他数据库没有这个问题。
all_books = models.Book.objects.filter(pub_date__year=2019,pub_date__month=2)
5、删除记录与修改记录
(1)删除————delete
(1-1)方法一:QuerySet对象调用delete方法
models.Book.objects.filter(price=100).delete()
(1-2)方法二:用model对象
models.Book.objects.filter(price=100).first().delete()
(2)修改————update
注意必须要用QuerySet对象调用
models.Book.objects.filter(title='西游记').update(title='水浒传')