1、测试脚本
"""
当你只是想想测试django中的某一个 py文件内容,那么你可以不用书写前后端交互的形式,而是直接写一个测试脚本即可
脚本代码无论写在应用下的tests.py还是写在自己单独开设的py文件都可以
"""
import os
def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'day06.settings')
import django
django.setup()
from app01 import models
......
if __name__ == '__main__':
main()
2、单表操作
2. 1、表准备
"""
Django自带的sqlite3对日期格式不是很敏感,处理的时候容易出错
"""
class User(models.Model):
name = models.CharField(max_length=32, verbose_name='姓名')
age = models.IntegerField()
register_time = models.DateField()
"""
DateTime
DateTimeField
两个重要参数,
auto_now :每次操纵数据的时候,该字段会自动将 当前时间更新
auto_now_add :在创建数据的时候,会自动将当前创建时间记录下来,之后只要不修改,那么就一直不变
"""
2. 2、操作
1.create()
2.对象.save()
1.all()
2.filter()
3.get()
1.update
2.对象.save()
1.delete()
2.对象.delete()
"""在实际项目中,数据是不可能真正删除的,一般情况下都用一个字段来标记是否删除"""
from django.test import TestCase
import os
def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'day06.settings')
import django
django.setup()
from app01 import models
增
删
"""
pk会 自动查找到当前表的主键字段,指代的就是当前表的主键字段
用了pk就不需要知道当前表的主键字段到底叫什么了
"""
修改
"""
get方法返回的直接就是当前数据对象
但是不推荐使用,
一旦数据不存在,该方法直接报错
而filter不会报错,返回空
"""
2.3、常见13种单表查询方法
all()
models.User.objects.all()
filter()
models.User.objects.filter()
models.User.objects.filter(pk=2)
get()
user_pbj = models.User.objects.get(pk=4)
first()
user_obj=models.User.objects.filter(pk=1).first()
models.User.objects.all().first()
last()
models.User.objects.all().last()
values()
models.User.objects.values('name')
values_list()
res=models.User.objects.values_list('name','age')
distinct()
res=models.User.objects.values('name','age').distinct()
order_by()
res=models.User.objects.order_by('age')
res=models.User.objects.order_by('-age')
reverse()
res=models.User.objects.order_by('age').reverse()
count()
res=models.User.objects.count()
exclude()
res=models.User.objects.exclude(name='zhao')
exists()
res=models.User.objects.exists()
res=models.User.objects.filter(pk=2).exists()
代码
values()
values_list()
"""
上述查看sql语句的方式,只能用于queryset对象
只有queryset对象才能够.query查看内部的sql语句
"""
order_by()
reverse()
res=models.User.objects.order_by('age').reverse()
print(res)
count()
res=models.User.objects.count()
print(res)
exclude
3、Django终端打印SQL语句
res = models.User.objects.values_list('name', 'age')
print(res.query)
"""
上述查看sql语句的方式,只能用于queryset对象
只有queryset对象才能够.query查看内部的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',
},
}
}
4、神奇的双下划线
"""神奇的双下划线"""
res=models.User.objects.filter(age__gt=18)
res=models.User.objects.filter(age__lt=18)
res=models.User.objects.filter(age__lte=18)
res=models.User.objects.filter(age__gte=18)
res=models.User.objects.filter(age__in=[18,32,40])
res=models.User.objects.filter(age__range=[18,40])
print(res)
res = models.User.objects.filter(name__contains='o')
print(res)
res=models.User.objects.filter(name__icontains='p')
res = models.User.objects.filter(name__startswith='j')
res = models.User.objects.filter(name__endswith='j')
res=models.User.objects.filter(register_time__month='1')
res=models.User.objects.filter(register_time__day='12')
res=models.User.objects.filter(register_time__week_day='1')
res=models.User.objects.filter(register_time__year='2000')
5、多表操作
5. 1、表准备
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8, decimal_places=2)
publish_data = models.DateField(auto_now_add=True)
publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
author = models.ManyToManyField(to='Author')
class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
email = models.EmailField()
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)
class AuthorDetail(models.Model):
phone = models.BigIntegerField()
addr = models.CharField(max_length=32)
"""切记执行表的迁移命令"""
5. 2、一对多外键增删改
5. 3、多对多外键增删改
add 给第三张关系表添加数据,括号内既可以传数字,也可以传对象,并且都支持多个
remove 括号内既可以传数字,也可以传对象,并且都支持多个
set 括号内必须传一个可迭代对象,括号内既可以传数字,也可以传对象,并且都支持多个, 先删除后新增
clear 清空对应的关系数据 括号内不加任何参数
"""多对多 增删改查 就是在操作第三张表"""
"""
add 给第三张关系表添加数据,括号内既可以传数字,也可以传对象,并且都支持多个
"""
book_obj = models.Book.objects.filter(pk=2).first()
"""
remove 括号内既可以传数字,也可以传对象,并且都支持多个
"""
"""
set 括号内必须传一个可迭代对象,括号内既可以传数字,也可以传对象,并且都支持多个,
先删除后新增
"""
book_obj.author.clear()
"""
clear 括号内不加任何参数
"""
5. 4、正反向概念
外键字段在我手上,那么我查你就是正向
外键字段不在我手上,我查你就是反向
book>>>外键字段在书那(正向)>>>publish
pupblish >>>外键字段在书那(反向)>>>book
"""
正向查询按字段
反向查询按表名小写
"""
5. 5、多表查询
1. 子查询(基于对象的跨表查询)
"""
在书写orm语句的时候,跟写sql 语句是一样的
不要企图一次性写完,如果比较复杂,就写一点看一点
正向什么时候需要加.all()????
当结果可能有多个,就需要加.all()
如果是一个则直接拿到数据对象
"""
"""
基于对象
反向查询的时候
当你的查询结果可以有多个的时候,就必须加_set.all()
当结果只有一个的时候,就不许需要加_set.all()
"""
2.联表查询(基于双下划线的跨表查询)
"""基于双下划线的跨表查询"""
"""反向"""
"""反向"""
"""反向"""
"""反向"""
6、聚合查询
"""聚合查询 aggregate"""
"""聚合函数通常都是配合分组一起使用的,也可以单独使用,需要借助于aggregate"""
from django.db.models import Max, Min, Sum, Count, Avg
res = models.Book.objects.aggregate(Max('price'), Min('price'), Sum('price'), Avg('price'))
print(res)
7、分组查询
"""分组查询 annotate"""
"""
MySQL分组之后默认只能获取到分组的依据,组内其他字段都无法直接获取了,
严格模式
ONLY_FULL_GROUP_BY
"""
# 1统计每一本书的作者个数
from django.db.models import Max, Min, Sum, Count, Avg
# res = models.Book.objects.annotate() # models后面点什么,就是按什么分组
# res = models.Book.objects.annotate(author_number=Count('author__id')).values('title','author_number')
# res1 = models.Book.objects.annotate(author_number=Count('author')).values('title','author_number')
"""
author_number是自己定义的字段,用来存储统计出来的每本书对应的作者个数
"""
# print(res1)
# 2统计每个出版社卖的最便宜的书的价格
# res = models.Publish.objects.annotate(bargain=Min('book__price')).values('name','bargain')
# print(res)
# 3统计不止一个作者的图书
# 1.先按照图书分组,求每一本书对应的作者个数
# 2过滤出不止一个作者的图书
# res = models.Book.objects.annotate(author_num=Count('author')).filter(author_num__gt=1).values('title', 'author_num')
"""只要你的orm 语句得出的结果还是一个queryset对象那么就可以无限制的点queryset方法"""
# print(res)
# 4查询每个作者出版的书的总价格
# res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name', 'sum_price')
# print(res)
"""
如果向按照指定的字段分组
models.Book.objects.values('price').annotate()
"""
"""
如果分组查询报错,
需要修改数据严格模式
"""
8、F与Q查询
8. 1、F查询
"""F查询"""
"""能够直接获取到表中某个字段对应的数据"""
from django.db.models import F
res = models.Book.objects.filter(maichu__gt=F('kucun'))
print(res)
res = models.Book.objects.update(price=F('price') + 50)
print(res)
"""
在操作字符类型的数据的时候,F不能够直接做到字符串的拼接
"""
from django.db.models import Value
from django.db.models.functions import Concat
res = models.Book.objects.update(title=Concat(F('title'), Value('爆款')))
print(res)
8. 2、Q查询
"""Q查询"""
"""能够改变多个查询条件之间的关系:与或非"""
from django.db.models import Q
"""Q包裹,逗号分割还是and关系,"""
"""竖杠就是or关系"""
"""~就是not关系"""
"""Q高阶用法 能够将查询条件变成字符串的形式"""
q = Q()
q.connector='or'
q.children.append(('maichu__gt', 200))
q.children.append(('price__lt', 50))
res = models.Book.objects.filter(q)
print(res)
9、Django中开启事务
"""
MySQL中:
事务
ACID
A:原子性 不可分割的最小单位
C:一致性 跟原子性是相辅相成的
I:隔离性 事务之间互相不干扰
D:持久性 事务一旦确认永久生效
事务的回滚
roollback
事务的提交
commit
"""
from django.db import transaction
try:
with transaction.atomic():
pass
except Exception as e:
print(e)
10、orm中常用字段及参数
AutoField
主键字段 primary_key=True
CharField
max_length字符长度 verbose字符的注释 对应到数据库是varchar
IntegerField int
BigIntegerField bigint
DecimalField
max_digits=8, decimal_places=2
EmailField varchar(254)
DateField date
DateTimeField datetime
auto_now :每次修改数据都会自动更新当前时间
auto_now_add:只在创建数据的时候记录时间,后续不会修改
BooleanField 布尔类型
该字段传布尔值(False/True),数据库里存0/1
TextField 文本类型
该字段可以存大段内容(文章、博客....),没有字数限制
FileField
upload_to='/data' 给该字段传一个文件对象,会自动将文件保存到/data目录下,然后将文件路径保存到数据库中/data/a.txt
"""其他字段参考博客"""
https://www.cnblogs.com/Dominic-Ji/p/9203990.html
class MyCharField(models.Field):
def __init__(self, max_length, *args, **kwargs):
self.max_length = max_length
super().__init__(max_length=max_length, *args, **kwargs)
def db_type(self, connection):
"""
返回真正的数据类型及各种约束条件
:param connection:
:return:
"""
return 'char(%s)' % self.max_length
myfield=MyCharField(max_length=16,null=True)
11、数据库查询优化
only与defer 正好相反
select_related与prefetch_related 跟跨表操作有关
"""
orm语句的特点:惰性查询,如果仅仅只是书写了orm语句,在后面没有用到该语句所查询出来的参数,那么orm 会自动识别,直接不执行
"""
only
res=models.Book.objects.only('title')
for i in res:
print(i.price)
defer
res=models.Book.objects.defer('title')
for i in res:
print(i.price)
"""defer与only刚好相反
defer括号内放到字段不在查询出来的对象里面,查询该字段需要重新走数据
而如果查询的是非括号内的字段,则不需要走数据库
"""
select_related
res = models.Book.objects.select_related('publish')
"""
select_related内部直接将book表与publish表连接起来,然后一次性将大表里面的所有数据全部封装给查询出来的对象
这个时候对象无论是点击book表的数据还是publish数据都无需再走数据查询了
select_related括号内只能放外键字段
只能放一对一 ,一对多,
不能放多对多
"""
for i in res:
print(i.publish.name)
prefetch_related
res=models.Book.objects.prefetch_related('publish')
"""
prefetch_related该方法内部是子查询
将子查询查询出来的所有结果也封装到对象中,
给你的感觉好像也是一次查询数据库
"""
for i in res:
print(i.publish.name)
|