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))