django框架基础-ORM操作-长期维护-20191213
############### ORM介绍和使用mysql的基本配置 ################
# ORM简介
# O是object,对象
# R是relation,关系,这是关系数据库中的表
# M是mapping,映射
# 在django里面主要是在models.py文件里面设计模型类,
###########################
# ORM另一个作用:根据设计的类生成数据库中的表
# django中使用ORM创建表
# 这种可以使用写Python语句,然后自动翻译成为sql语句,但是这种写的sql执行的效率和大神程序员写的还是有差距的,
# 类--数据表
# 对象--数据行
# 属性--字段,理清了这三点,ORM就没有问题
# ORM回顾,对象关系映射,object relational mapping,
# 优点:让软件开发人员专注于业务逻辑的处理,提高了开发效率。
# 缺点:一定程度上降低了程序的执行效率,有一个把orm翻译成sql的过程,如果一个公司对执行效率要求比较高
# 配置使用mysql数据库
# 第一步:在项目目录下-项目文件夹下-settings文件中,
DATABASES = {
‘default‘: {
‘ENGINE‘: ‘django.db.backends.mysql‘,
‘NAME‘: ‘XXX‘,
‘USER‘: ‘root‘,
‘PASSWORD‘: ‘XXX‘,
‘HOST‘: ‘localhost‘,
‘PORT‘:3306,
}
}
# 第二步:在项目目录下-项目文件夹下-__init__文件中,
import pymysql
pymysql.install_as_MySQLdb()
#创建数据库
# ORM可以操作数据表,操作数据行,但是不能创建数据库,需要自己创建数据库,这是使用mysql的情况下
# 如果你使用SQLite,你不需要事先创建任何东西 —— 数据库文件将会在需要的时候自动创建。
cmd
mysql -uroot -p
create database XXXXX;
use django
show tables;############### 使用ORM创建表 ################
from django.db import models
class Publisher(models.Model):
‘‘‘出版社表‘‘‘
id = models.AutoField(primary_key=True)
name=models.CharField(max_length=64,null=False,unique=True)
addr=models.CharField(max_length=120,default=‘上地出版社‘)
def __str__(self):
# 返回出版社的名称
return self.name
class Meta: # 定义一个元类
db_table=‘Publisher‘
# 指定对应的表名
# 工作中一定要指定表名,否则改动了程序app的名字,迁移的时候就会出问题,
class Book(models.Model):
‘‘‘书籍表‘‘‘
id = models.AutoField(primary_key=True)
title=models.CharField(max_length=64,null=False,unique=True)
# ForeignKey,出版社和书关系是一对多的关系,,使用外键ForeignKey,
# to=Publisher,数据库中实际没有这个publisher,实际是这个publisher_id
publisher=models.ForeignKey(to=Publisher,on_delete=models.CASCADE,related_name=‘books‘)
price=models.DecimalField(max_digits=5,decimal_places=2,default=99.99)
inventory_num=models.IntegerField(default=1000)
sales_num=models.IntegerField(default=0)
pub_data=models.DateField()
def __str__(self):
return self.title
class Author(models.Model):
‘‘‘作者表‘‘‘
name = models.CharField(max_length=64, null=False, unique=True)
age = models.IntegerField(default=18)
phone = models.BigIntegerField(default=18753333333)
# ManyToManyField,作者和书之间是多对多关系
# 在数据库中是通过第三张表建立多对多的关系的,
book = models.ManyToManyField(to=‘book‘)
detail=models.OneToOneField(to=‘AuthorDetail‘,null=True,unique=True)
#一个作者对应一个作者详情,
#为什么这么做,因为作者表用的非常的频繁,每一次查的时候都要全表查,数据量大,但是用到的字段不多,
#所以把常用的字段抽离出来,比如列表页和详情页,这些都是需要分离的,为了更快的查询,
def __str__(self):
return self.name
class AuthorDetail(models.Model):
hobby=models.CharField(max_length=32)
addr=models.CharField(max_length=128)执行命令:
# 执行命令,这样表就创建了 python manage.py makemigrations #把改动记录到文件中, python manage.py migrate #迁移 # 在django中的ORM操作数据库表: # 删除数据表,注释掉整个建表的类, # 执行语句,这样就删除表了, python manage.py makemigrations python manage.py migrate # 修改字段一样,修改表字段, # 执行语句, python manage.py makemigrations python manage.py migrate
############### django -ORM常用的字段和选项 ################
# ORM的具体使用:
# 定义模型类的时候,字段名的要求:
# 1,不能是python关键字,
# 2,字段名中不能出现连续的下滑线
# 语法:
# 属性名=models.字段类型(选项)
###############
# ORM里面的字段类型和选项:
# 1,ORM常用的字段
from django.db import models
class Test(models.Model):
id = models.AutoField(primary_key=True) # AutoField 自动增长的整型,primary_key 主键
isnum=models.BooleanField() # BooleanField 布尔字段,值为True或者False
# isnum2=models.NullBooleanField # NullBooleanField 支持null,True,False三种,这个一般不用
name = models.CharField(max_length=20,unique=True) # CharField 字符串,max_length最大长度
text=models.TextField() # 大文本字段,一般超过4000个字符串的时候使用,比如新闻内容
age=models.IntegerField() # IntegerField 整数 一个整数类型,范围在 -2147483648 to 2147483647。10位,所以不能用来存手机号,
price=models.DecimalField(max_digits=10,decimal_places=2) # DecimalField 十进制的浮点数,max_digits这是总位数,decimal_places这是小数位数
# price2 =models.FloatField(max_digits=10,decimal_places=2) # 这个和上面的那个精度不同,这个存进计算机和拿出来是有差异的,比不上DecimalField,只要是钱的问题,都是用DecimalField
create_time=models.DateField(auto_now_add=True) # DateField日期,auto_now_add,----每次新增的时候添加时间为当前时间,
update_time = models.DateField(auto_now=True) # DateField日期,auto_add----每次修改的时候更改时间,和auto_now_add这两个不能同时使用,
time=models.TimeField() # 参数同上,这是小时,分,秒,DateField这是年月日,
data_time=models.DateTimeField(null=False) # 参数同上,这是年月日,时分秒,
file=models.FileField() # FileField 上传文件字段,
image=models.ImageField() # 继承于FileField,对上传的内容进行校验,确保是一个图片
# 2,ORM常用的选项:
# default 设置默认值 eg:default="123"
# primary_key 设置主键 eg:primary_key=True
# unique 设置唯一值,eg:unique=True
# db_index 设置索引,eg:db_index=True,这就比如你查字典的时候先查索引,然后再往后查
# db_column 设置字段的名字,eg:db_column=‘title‘这样生成表的时候,会按照这个名字
# null 设置是否为空,eg:null=True,默认是不能空的,
# blank 如果是True,就是这个字段允许是空白,默认是False,这个是后台管理页面表单验证范畴的,
# 注意:default和blank不影响表的结构,不需要做迁移,其他的都要迁移,############### django -ORM单表查询函数 ################
from app01 import models
from django.http import HttpResponse
from datetime import date
from django.db.models import Q
from django.db.models import F
from django.db.models import Sum, Min, Max, Count, Avg
def ORM(request):
# ORM一般操作,必知必会13条:
# 返回queryset对象的:
all_book = models.Book.objects.all() # 返回所有数据,结果是可以遍历的
book1 = models.Book.objects.filter(id=1) # 返回满足条件的数据
book2 = models.Book.objects.values() # 这是把所有字段拿出来了,这是一个字典序列,values(‘name‘,‘create_time‘) #可以指定字段,
book3 = models.Book.objects.values_list() # values_list(‘name‘,‘create_time‘) #这是返回的一个元组,
book4 = models.Book.objects.exclude(id=1) # 返回不满足条件的数据
# book5 = models.Book.objects.order_by(‘id‘) # 对结果排序,升序
# book5 = models.Book.objects.order_by(‘-id‘) # 对结果排序,降序,在字段前面加减号,
book5 = models.Book.objects.filter(id__lt=3).order_by(‘-id‘) # 对过滤结果进行排序
book6 = models.Book.objects.reverse()
book7 = models.Book.objects.distinct()
# 返回具体对象的:
book8 = models.Book.objects.get(id=1) # 查不到数据会报异常,所以一般不用这个,返回的结果中有且只有一条数据,有多条数据,也会报异常
book9 = models.Book.objects.first()
book10 = models.Book.objects.last()
# 返回布尔类型
book11 = models.Book.objects.exists() # 判断查询集里面有没有数据,如果有就是True,没有就是False,括号里面不需要有值
# 返回数量
book12 = models.Book.objects.count()
##################################
# 模糊查询:
book13 = models.Book.objects.filter(title__contains=‘红‘) # 包含红的,
book14 = models.Book.objects.filter(title__endswith=‘志‘) # 以志结尾的,
book14 = models.Book.objects.filter(title__startswith=‘西‘) # 以西开头的
# 查询书名不为空的书
book14 = models.Book.objects.filter(title__isnull=False)
# 范围查询
book14 = models.Book.objects.filter(id__in=[2, 3])
# 比较查询
book15 = models.Book.objects.filter(id__gt=3) # id大于3,great
book15 = models.Book.objects.filter(id__lt=3) # id小于3 less
book15 = models.Book.objects.filter(id__gte=3) # id大于等于3 equal
book15 = models.Book.objects.filter(id__lte=3) # id小于等于3 equal
# 日期查询
# 查询1980年出版的图书
book16 = models.Book.objects.filter(pub_data__year=1980)
# 查询1980年1月1日后发布的图书
book17 = models.Book.objects.filter(pub_data__gt=date(1981, 1, 1))
###################################
# Q对象,表示查询条件之间的逻辑关系,与&,或 | 非~(波浪号),
# 查询id大于3并且价格大于100的书
book18 = models.Book.objects.filter(id__gt=3, price__gt=100)
book19 = models.Book.objects.filter(Q(id__gt=3) & Q(price__gt=90))
# 这是第二种写法
# 查询id大于3或价格大于100的书
book19 = models.Book.objects.filter(Q(id__gt=3) | Q(price__gt=90))
# 查询id不等于1的书籍
book20 = models.Book.objects.filter(~Q(id=1))
# F对象,用于类属性之间的比较,
# 查询图书的价格大于库存数量的书籍
book21 = models.Book.objects.filter(price__gt=F(‘inventory_num‘))
# 查询价格大于2倍库存数量的图书信息
book22 = models.Book.objects.filter(price__gt=F(‘inventory_num‘) * 2)
#####################
# 查询集
# 使用all,filter,exclude,orderby,调用这些函数会产生一个查询集,querySet类对象可以使用继续调用上面的所有函数
# 惰性查询,就是说你不展示数据的时候,是不查询数据库的,
book1 = models.Book.objects.all() # 返回一个查询集,这一句还没有查询数据库,最后return的时候才才去查数据库
# 缓存,就是说你第一次查过了,就会进入缓存,下次不会再次查询一次了,
# 对查询集可以进行切片,切换之后就和原来的查询集没有关系了,
book2 = models.Book.objects.all()
book2 = book2[0:2]
return HttpResponse(book23)############### django-多表查询 ################
if __name__ == "__main__":
import os,django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_django.settings")
django.setup()
from app01 import models
# 模型类关系
# 表之间有三种关系,
# 一对多,出版社和作者,ForeignKey,注意:这种关系必须写在多的表中,
# 多对多,作者和书籍,ManyToManyField,这种定义在哪一个表都可以,
# 一对一,作者和作者详情,OneToOneField,这种定义哪一个表都可以,
# 外键的跨表查询
# 正向查找,这是查询书籍id为1的出版社的名字
# 基于对象:
# book1 = models.Book.objects.first()
# publiseh1 = book1.publisher.name
# 基于下划线的:
book2 = models.Book.objects.filter(id=1).values("publisher__name")
# 反向查找
# 基于对象
publisher_obj = models.Publisher.objects.get(id=1)
# book3=publisher_obj.book_set.all()
# 如果在外键中设置了related_name = books
book3 = publisher_obj.books.all()
# 基于下划线的,
# models.Publisher.objects.filter(id=1).values(‘book__title‘)
# 如果在外键中设置了related_name = books
book4 = models.Publisher.objects.filter(id=1).values("books__title")
# 逆向查询, 需要加上表名__字段名
# 查询图书信息,要求图书信息关联的作者中包含:曹
book5 = models.Book.objects.filter(author__name__contains=‘曹‘)
# 正向查询,需要是字段名__对应表的字段名
# 查询书名为三国志的作者,
author6 = models.Author.objects.filter(book__id=1)
#########################
# 多对多操作
# 作者和书籍就是多对多的,
# 通过作者创建一本书籍
author_obj = models.Author.objects.first()
from datetime import date
# author_obj.book.create(title=‘鬼吹灯‘,publisher_id=1,price=123,inventory_num=123,sales_num=123,pub_data=date(1999,1,1))
# book_obj = models.Book.objects.first()
# author_obj.book.add(book_obj) #这是添加一个,
book_obj=models.Book.objects.filter(id__gt=4)
# author_obj.book.add(*book_obj)
# author_obj.book.add(8)
# set()更新model对象的关联对象
# author_obj.book.remove(book_obj)
# author_obj.book.clear()
# 额外补充,外键的反向操作,
# 找到id=1的出版社,
# publisher_obj = models.Publisher.objects.get(id=1)
# publisher_obj.books.clear() # 这个只是把书关联的出版社字段清空了,这本书还在,
# 对于ForeignKey对象,clear()和remove()方法仅在null=True时存在。print(ret3)############### django--聚合和分组 ################
if __name__ == "__main__":
import os,django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_django.settings")
django.setup()
from app01 import models
from django.db.models import Count,Sum
# 聚合函数;
# 查询所有书的数目
book23 = models.Book.objects.all().aggregate(Count(‘id‘)) # 这是返回一个字典
book23 = book23.values()
book23 = models.Book.objects.all().count() # 这是返回一个数字,不是字典,
# 书籍销量总和
book24 = models.Book.objects.all().aggregate(Sum(‘inventory_num‘)).values() # 返回也是一个字典
# 最大和最小就是一样的使用方法
# ret=models.Book.objects.all().aggregate(price_avg=Avg(‘price‘),price_max=Max(‘price‘),price_min=Min(‘price‘),price_sum=Sum(‘price‘))
# print(ret.get(‘price_max‘)) #可以通过这种方式把值取出来,
# 分组
# 逻辑:
# 根据书分组,
# 然后配合聚合函数,求作者的数量
# 然后数量就是一个属性,就可以拿出来了,
ret1 = models.Book.objects.all().annotate(author_num=Count(‘author‘)) # count里面是表名,
# ret1是把所有的书查询出来了,但是里面的具体的书是多了一个属性就是author_num,
for book in ret1:
print(book.author_num)
print(type(book))
# 对结果还可以进行过滤,
ret2 = models.Book.objects.all().annotate(author_num=Count(‘author‘)).filter(author_num__gt=1)
# 查询出各个作者出版的书的总价格
# 逻辑:
# 1,查询所有的作者,
# 2,根据每一个作者分组,加上一个总价price_sum,这个时候每一个字段就是一个属性,
# 3,然后取出price_sum
# 所以连接了三张表,,
ret3 = models.Author.objects.all().annotate(price_sum=Sum(‘book__price‘)).values_list( ‘name‘, ‘price_sum‘)
print(ret3)############### django--ORM进行增删改查操作 ################
if __name__ == "__main__":
import os,django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_django.settings")
django.setup()
from app01 import models
# 使用ORM进行增删改查操作,
# 查询:
ret = models.Publisher.objects.all()
# 创建:
# models.Publisher.objects.create(name=‘五棵松‘,addr=‘望京‘)
# 删除:
# models.Publisher.objects.get(id=4).delete()
# 修改:
ret2 = models.Publisher.objects.first()
ret2.name=ret2.name+‘123‘
ret2.save() # 修改的时候一定要有这个
# 一对多的修改,
# 前端传入id,new_book_title,new_publisher_id
# edit_id=1
# new_book_title=‘水浒传‘
# new_publisher_id=1
# edit_book_obj = models.Book.objects.get(id=edit_id)
# edit_book_obj.title = new_book_title
# edit_book_obj.publisher_id = new_publisher_id
# edit_book_obj.save() # 保存
# 多对多的修改,
edit_id=6
new_author=‘南派三叔‘
new_publisher_id=1
new_books=(1,2)
edit_author_obj = models.Author.objects.get(id=edit_id)
edit_author_obj.name = new_author
edit_author_obj.book.set(new_books) # 这种表关联的方式是符合更新值的,这个要记住,new_books是书的id,可以是多个值,
edit_author_obj.save()
print(ret)############### django--orm多对多的三种方式 ################
if __name__ == "__main__":
import os,django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_django.settings")
django.setup()
from app01 import models
# orm多对多的三种方式
#多对多的方式
# 1,orm自动帮我创建第三张表,书和作者之间的第三张表就是自动创建的,
# 2,自己创建第三张表,利用外键分别关联作者和书,查询比较麻烦
# 3,自己创建第三张表,使用orm的manyTomanyField,制定一下,
# book=models.ManyToManyField(to=‘book‘,through=‘Author2Book‘,through_fields=("author","book"))
#第三种的查询方式和第一种的查询方式一样的,因为已经做了关联了,
# 我们使用第几种,
#如果第三张表没有额外的字段,就使用第一种方法,
#如果第三张表有额外的字段,这种可以使用第三种方法和第一种方法,
# 比如相亲网站,一个男的可以联系多个女的,一个女的也可以联系多个男的,这就是多对多的,
#约会记录,多对多,这个表的结构,
#id boy_id girl_id date 约会时间,
# 注意:
#第三种方式,这种add() remove() 就没有了,
# 举例:
# 从作者关联的书里面移除id是1的书
# 之前使用第一种方法的时候是:
# models.Author.objects.get(id=1).book.remove(1)
# 现在自己建第三张表,就不能使用这种方式了,
# models.Author2Book.objects.get(author_id=1,book_id=1).delete()
#在app01里面查询id=1的作者关联的书,
# author_obj=models.Author.objects.get(id=4)
# ret=author_obj.book.all()
# print(ret)
#在app02里面查询id=1的作者关联的书,
# author_obj=models.Author.objects.get(id=4)
# ret=author_obj.book.all()
# print(ret)
#如果是你自己创建的第三张表,就不能使用这种方法了,因为里面没有book这个属性啊,
#怎么拿?
#先拿到作者为1的数据,在关联表
ret=models.Author2Book.objects.filter(author_id=4).values_list(‘book_id‘)
print(ret)#<QuerySet [(4,), (5,)]>
ret=[i[0] for i in ret] #看来列表推导式还是需要研究一下
ret=models.Book.objects.filter(id__in=ret)
print(ret)
#所以这种自己建立第三张表是比较麻烦的,############### django--事务,原子操作 ###############
if __name__ == "__main__":
import os,django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_django.settings")
django.setup()
from app01 import models
import datetime
# 事务,原子操作,
try:
from django.db import transaction #导入一个transaction
with transaction.atomic(): #atomic原子,下面的语句要么都成功,要么都不成功,这样就可以了,这就是事务,
new_publisher = models.Publisher.objects.create(name="火星出版社")
models.Book.objects.create(title="橘子物语", publish_date=datetime.date.today(), publisher_id=10) # 指定一个不存在的出版社id
except Exception as e:
print(str(e))