Day49 orm 操作 Django单表操作
1、ORM简介
对象关系映射(Object Relational Mapping,简称ORM)。简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。
ORM在业务逻辑层和数据库层之间充当了桥梁的作用。咱们通过一张图来介绍一下数据库与python代码之间的一个关系,请看下图:
ORM的优点:
- 不用写繁琐的SQL语句,用咱们熟悉的python代码,就能实现对数据的操作,提高开发效率;
- 可以平滑的操作,切换数据库。
ORM的缺点:
- ORM代码转换为SQL语句时,需要花费一定的时间,执行效率会有所降低
- 长期写ORM代码,导致写SQL语句能力,会有所减弱。
- 如果想打印orm转换过程中的sql,需要在settings中进行如下配置:
只需要把这段代码加载到setting中即可:
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就是pycharm中的MySQL语句就行一个桥梁就行内部的访问。
类似于mysql.、Navicat、本地cmd都是客户端去连接远程的mysql服务端,mysql服务端是mysqld。
内部的流程是: python(orm)先转化成SQL语句,然后利用pymysql模块就行和mysql服务端就行相互连接。
2.单表操作
2.1、Django如何使用MySQL数据库
-
1创建MySQL数据库。
注意:ORM无法操作到数据库级别,只能操作到数据表。
如下:在本地数据库中创建一个编码格式为utf8的book_demo 的测试数据库
create
database
book_demo
default
charset=utf8; # 防止编码问题,指定为utf8.
-
2 settings.py里设置
1 首先是找到数据库中的
注意:
如果老师让交作业的时候红色框中的数据库是可以不用修改的,他会生成一个文件数据库sqlite3的,不需要配置!!!
## 但是这里 我们需要使用本地的mysql需要配置,配置如下:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': '数据库名', 'HOST': '数据库IP地址', 'PORT': 3306, 'USER': 'root', 'PASSWORD': '', } }
-
3告诉Django使用pymysql模块连接mysql数据库
# 在与settings.py同级目录下的__init__.py中
import pymysql pymysql.install_as_MySQLdb()
-
4创建模型(在models.py中写类)
class Book(models.Model): id = models.AutoField(primary_key=True) title = models.CharField(max_length=32) # 书籍名称 price = models.DecimalField(max_digits=5, decimal_places=2) # 书籍价格 publisher = models.CharField(max_length=32) # 出版社名称 pub_date = models.DateField() # 出版时间
- 扩展:更多字段和参数
- 更多字段:
- 更多参数:参考陈老师的博客
- 5执行数据量迁移的命令
python manage.py makemigrations # 把models.py的变更记录记录下来 python manage.py migrate # 把变更记录的操作同步到数据库中
报错的话:
MySQLclient目前只支持到python3.4,因此如果使用的更高版本的python,需要修改如下:
需要把上面报错文件中的base,py
if version < (1, 3, 3): raise ImproperlyConfigured("mysqlclient 1.3.3 or newer is required; you have %s" % Database.__version__)
注释掉就可以了。
6.查看本次orm关联的数据库day49
不要轻易删除这个表中的文件,以及在Django中相关联的那条记录。默认在数据中创建10张表格。
看看django_migrations 中的和数据库中一一对应的关系是,要删除的话,对应的一起删除 否则会报错!
3. 单表操作
3.1添加表记录
- 方式一:
通过类实例化对象的方式。注意:一定要对象.save()
book = models.Book(title="吸星大法", price=200, publisher="明教出版社", pub_date="2018-12-12") book.save()
运行代码:Book object (1), Book object (1) <class 'app01.models.Book'>
- 方式二:
通过ORM提供的objects提供的方法 create来实现。
book = models.Book.objects.create(title="独孤九剑", price=150, publisher="华山出版社", pub_date="2019-1-12")
小结:使用方式2的方法不用手动就行保存。推荐使用。
3.2查询表记录
1、查询API
<1> all(): 查询所有结果
def book_list(request): # all 查询所有 books = models.Book.objects.all() # QuerySet类型 类似于list, 里面是一个个对象 # 类似于sql: select * from app01_book # 查询结果是 <QuerySet [<Book: Book object (1)>, # <Book: Book object (2)>, <Book: Book object (3)>, # <Book: Book object (4)>, <Book: Book object (5)>, # <Book: Book object (6)>, <Book: Book object (7)>, # <Book: Book object (8)>, <Book: Book object (9)>, # <Book: Book object (10)>, <Book: Book object (11)>, # <Book: Book object (12)>, <Book: Book object (13)>, # <Book: Book object (14)>]> <class 'django.db.models.query.QuerySet'> # 如果在对象的方法中添加魔术属性的对象的时候,可以将打印出来的变成我们想要的东西,这里我们把print(book)用魔术属性打印出其title属性 # def __str__(self): # return self.title # 1.加上上面的这句话,就会在打印对象的时候生效了!返回你想要的字符串 本次中返回的是对象的title属性 # 2.可以上边的可以看出models orm模型中每一个实力化对象就是对应中的每一条记录,也就是一个对象==一条记录 print(books, type(books)) return HttpResponse('查询成功!')
<2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象
# filter 过滤 books = models.Book.objects.filter(pk=3) # QuerySet 类似于list, 满足条件的对象集 # 1.filter相当于 select * from app01_book where pk=3 # 2.<QuerySet [<Book: 易经2>]> <class 'django.db.models.query.QuerySet'>
<3> get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,
如果符合筛选条件的对象超过一个或者没有都会抛出错误。
# get 获取一个对象 # 直接获取出对象 注意: 当查询条件不存在或者查询出结果有多个值时,会报错。 # 存在 books = models.Book.objects.get(pk=4) # 易经筋 <class 'app01.models.Book'>,打印出来的易经筋本来是打印出的对象,由于魔术方法str导致的,记得!! # 不存在 都是直接获取出对象 # books = models.Book.objects.get(pk=18) # app01.models.Book.DoesNotExist: Book matching query does not exist. # 都是直接获取出对象,获取有多个对象的时候会报错! # books = models.Book.objects.get(price=200)
<4> exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象,是QuerySet 类似于list, 满足条件的对象集
# exclude 获取不满足的条件的 对象的集合 # 类似于not 排除满足条件的对象。剩下的取出来即可。 books = models.Book.objects.exclude(publish='少林出版社', price=200) print(books, type(books)) # <QuerySet [<Book: 易经>, <Book: 易经>, <Book: 易经2>, # <Book: 易经筋>, <Book: 易经筋>, <Book: 独孤九剑>, # <Book: 挤奶龙爪手>, <Book: 冲灵剑法>, <Book: 吸星大法>, # <Book: 葵花宝典>, <Book: 乾坤大挪移>, <Book: 九阴真经>, # <Book: 九阳神功>, # <Book: 九阴白骨爪>]> <class 'django.db.models.query.QuerySet'>
<5> order_by(*field): 对查询结果排序,容易的看出下面的确实相反的操作 一个升序 一个降序,都是对象多条表记录对象就行操作
# order by("price")默认是升序 # order by("-price") 按照价格就行倒序排 排的也是 books = models.Book.objects.order_by("price") # <QuerySet [<Book: 九阴白骨爪>, <Book: 易经筋>, # <Book: 易经筋>, <Book: 冲灵剑法>, <Book: 独孤九剑>, # <Book: 吸星大法>, <Book: 易经>, <Book: 易经>, <Book: 易经2>, # <Book: 挤奶龙爪手>, <Book: 九阴真经>, <Book: 九阳神功>, # <Book: 乾坤大挪移>, <Book: 葵花宝典>]> # <class 'django.db.models.query.QuerySet'> print(books, type(books)) books = models.Book.objects.order_by("-price") print(books, type(books)) # <QuerySet [<Book: 葵花宝典>, <Book: 乾坤大挪移>, # <Book: 九阳神功>, <Book: 九阴真经>, <Book: 易经>, # <Book: 易经>, <Book: 易经2>, <Book: 挤奶龙爪手>, # <Book: 吸星大法>, <Book: 独孤九剑>, <Book: 冲灵剑法>, # <Book: 易经筋>, <Book: 易经筋>, <Book: 九阴白骨爪>]> # <class 'django.db.models.query.QuerySet'>
<6> reverse(): 对查询结果反向排序,可以看出,第一按照price就行查询结果的升序排列,然后再使用reverse就行降序排列,感觉很累赘,感觉完全使用oder_by("-price")同第5个就搞定了啊
# reverse 默认是将查询结果就行返序列 默认是降序 books = models.Book.objects.order_by("price").reverse() # <QuerySet [<Book: 葵花宝典>, <Book: 乾坤大挪移>, # <Book: 九阳神功>, <Book: 九阴真经>, <Book: 易经>, # <Book: 易经>, <Book: 易经2>, <Book: 挤奶龙爪手>, # <Book: 吸星大法>, <Book: 独孤九剑>, <Book: 冲灵剑法>, # <Book: 易经筋>, <Book: 易经筋>, <Book: 九阴白骨爪>]> # <class 'django.db.models.query.QuerySet'> print(books, type(books))
<7> count(): 返回数据库中匹配查询(QuerySet)的对象数量。
# count # 14 <class 'int'> books = models.Book.objects.all().count() print(books, type(books)) # exists False <class 'bool'> books = models.Book.objects.filter(pk=18).exists() # 返回值为布尔值 print(books, type(books)) return HttpResponse('查询成功!')
<8> first(): 返回第一条记录 <9> last(): 返回最后一条记录
# first 与 last() 一般都要集合query对象结合使用,也就是说包含对象的集合使用。比如filter 返回的是一个query对象集合, # 从结果可以看出对象集合中只有一个对象 只要是对象集合就可以使用first() 什么last类似于索引讲具体的对象取出来 # books = models.Book.objects.filter(pk=4) # 得到query对象集合 # <QuerySet [<Book: 易经筋>]> <class 'django.db.models.query.QuerySet'> # 取出集合中的第一个的元素对象 books = models.Book.objects.filter(pk=4).first() print(books, type(books)) # 易经筋 <class 'app01.models.Book'> # 取出集合中的最后一个元素对象 # books = models.Book.objects.filter(pk=4).last() # 类似于get直接将对象取出来, # 易经筋 <class 'app01.models.Book'> print(books, type(books)) 注意:由于在 filter筛选的时候得到的集合时1个对象,即是第一个对象和最后一个对象都是一样的 哈哈!!
<10> exists(): 如果QuerySet包含数据,就返回True,否则返回False <11> values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 model的实例化对象,而是一个可迭代的字典序列,其中'title'和'price'对应的值就是数据库中的值!,整个返回的整体是一个Query对象
# values() books = models.Book.objects.filter(price=200).values('title', 'price') print(books, type(books)) # <QuerySet [ # {'title': '易经', 'price': Decimal('200.00')}, # {'title': '易经', 'price': Decimal('200.00')}, # {'title': '易经2', 'price': Decimal('200.00')}, # {'title': '挤奶龙爪手', 'price': Decimal('200.00')} # ]> # <class 'django.db.models.query.QuerySet'>
<12> values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
# values_list books = models.Book.objects.filter(price=200).values_list('title', 'price') print(books, type(books)) # <QuerySet [ # ('易经', Decimal('200.00')), # ('易经', Decimal('200.00')), # ('易经2', Decimal('200.00')), # ('挤奶龙爪手', Decimal('200.00')) # ]> # <class 'django.db.models.query.QuerySet'>
<13> distinct(): 从返回结果中剔除重复纪录
# distinct() books = models.Book.objects.filter(price=200).values() print(books, type(books)) # <QuerySet [ # {'id': 1, 'title': '易经', 'price': Decimal('200.00'), 'publish': '人民出版社', 'pub_date': datetime.date(2009, 12, 12)}, # {'id': 2, 'title': '易经', 'price': Decimal('200.00'), 'publish': '人民出版社', 'pub_date': datetime.date(2009, 12, 12)}, # {'id': 3, 'title': '易经2', 'price': Decimal('200.00'), 'publish': '人民出版社', 'pub_date': datetime.date(2009, 12,12)}, # {'id': 7, 'title': '挤奶龙爪手', 'price': Decimal('200.00'), 'publish': '华山出版社', 'pub_date': datetime.date(2019, 2,22)} # ]> # <class 'django.db.models.query.QuerySet'>
books = models.Book.objects.filter(price=200).values_list("price")
# <QuerySet [(Decimal('200.00'),), (Decimal('200.00'),)]> <class 'django.db.models.query.QuerySet'>
# books = models.Book.objects.filter(price=200).values_list("price").distinct()
# <QuerySet [(Decimal('200.00'),)]> <class 'django.db.models.query.QuerySet'>
3.3、基于双下划线的模糊查询
Book.objects.filter(price__in=[100,200,300]) Book.objects.filter(price__gt=100) Book.objects.filter(price__lt=100) Book.objects.filter(price__range=[100,200]) Book.objects.filter(title__contains="法") Book.objects.filter(title__icontains="python") # 不区分大小写 Book.objects.filter(title__startswith="九") Book.objects.filter(pub_date__year=2018)
# 基于双下划线的模糊查询 books = models.Book.objects.filter(price__range=[100, 200])# filter里面都是放的一个一个的对象 print(books, type(books)) # <QuerySet [ # <Book: 易经>, <Book: 易经>, <Book: 易经2>, <Book: 易经筋>, # <Book: 易经筋>, <Book: 独孤九剑>, <Book: 挤奶龙爪手>, # <Book: 冲灵剑法>, <Book: 吸星大法> # ]> # <class 'django.db.models.query.QuerySet'> books = models.Book.objects.filter(title__contains="法") print(books, type(books)) # <QuerySet [<Book: 冲灵剑法>, <Book: 吸星大法>]> <class 'django.db.models.query.QuerySet'> books = models.Book.objects.filter(title__startswith="九") print(books, type(books)) # <QuerySet [<Book: 九阴真经>, <Book: 九阳神功>, <Book: 九阴白骨爪>]> <class 'django.db.models.query.QuerySet'> books = models.Book.objects.filter(pub_date__year=2018) print(books, type(books)) # <QuerySet [<Book: 葵花宝典>]> <class 'django.db.models.query.QuerySet'>
3.4.删除表记录
def del_book(request): pk = request.GET.get("pk") print(pk) # 方式一 调用QuerySet的delete方法 # books = models.Book.objects.filter(pk=pk).delete() # 方式二 obj.delete() # books = models.Book.objects.get(pk=pk) # 当用户输入pk不存在时,还会报错,pass掉 books = models.Book.objects.filter(pk=pk).first() books.delete() print(books) return HttpResponse("删除成功!")
def del_book(request): pk = request.GET.get("pk") print(pk) # 方式一 调用QuerySet的delete方法 books = models.Book.objects.filter(pk=pk).delete() # 1,删除该条的时候如果存在直接返回 # 返回值是:(1, {'app01.Book': 1}) # 2.如果删除的时候该条记录不存在那么返回一个空的 # 方式二 obj.delete() # (0, {'app01.Book': 0}返回的意思是 在app01_book 中受影响的行数是0行,即是删除的数据不存在也不会报错! # books = models.Book.objects.get(pk=pk) # 当用户输入pk不存在时,还会报错,pass掉 # books = models.Book.objects.filter(pk=pk).first() # books.delete() print(books) return HttpResponse("删除成功!")
3.5、修改表记录
def edit_book(request): pk = request.GET.get("pk") # 方式一: 调用QuerySet的update方法 # books = models.Book.objects.filter(pk=pk).update(price=280) # 方式二: obj更改属性值, 必须要save()同步到数据库。 books = models.Book.objects.filter(pk=pk).first() books.price = 189 books.save() print(books) return HttpResponse("编辑成功!")
def edit_book(request): pk = request.GET.get("pk") # 方式一: 调用QuerySet的update方法 books = models.Book.objects.filter(pk=pk).update(price=280) print(books) # 1 更新条数 # 方式二: obj更改属性值, 必须要save()同步到数据库。 # books = models.Book.objects.filter(pk=pk).first() # books.price = 189 # books.save() # print(books) #挤奶龙爪手 是一个对象 只是魔术方法使打印对象变成了一个自己想打印的东西 这里打印的是对象的title属性 return HttpResponse("编辑成功!")