Django基础第三篇
一、ORM操作
1.常用字段和参数
Autofied
自增的整形字段,必填参数primary_key=True, 则成为数据库的主键,如无该字段,django自动创建
IntegerField
一个整形类型,数值范围-2147483648 ~ 2147483647
CharField
字符类型,必须提供max_length参数。max_length表示字符的长度
BooleanField 布尔
DecimalField 小数
FileField:文件路径
DateTimeeField
日期类型,日期格式YYYY-MM-DD
参数:
auto_now: 每次修改时修改为当前 日期时间 ps: 修改是当前时间也会变
auto_now_add: 新创建对象时自动添加当前日期时间 ps:新增是保持,修改是不会变
ps: auto_now_add auto_now 和default 是互斥的 同一时间只能选择一个
class Person(models.Model): pid = models.AutoField(primary_key=True) 修改主键 name = models.CharField(max_length=32) age = models.IntegerField() birth = models.DateTimeField(auto_now_add=True)
所有这段类型
AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) - bigint自增列,必须填入参数 primary_key=True 注:当model中如果没有自增列,则自动会创建一个列名为id的列 from django.db import models class UserInfo(models.Model): # 自动创建一个列名为id的且为自增的整数列 username = models.CharField(max_length=32) class Group(models.Model): # 自定义自增列 nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) SmallIntegerField(IntegerField): - 小整数 -32768 ~ 32767 PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正小整数 0 ~ 32767 IntegerField(Field) - 整数列(有符号的) -2147483648 ~ 2147483647 PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正整数 0 ~ 2147483647 BigIntegerField(IntegerField): - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807 BooleanField(Field) - 布尔值类型 NullBooleanField(Field): - 可以为空的布尔值 CharField(Field) - 字符类型 - 必须提供max_length参数, max_length表示字符长度 TextField(Field) - 文本类型 EmailField(CharField): - 字符串类型,Django Admin以及ModelForm中提供验证机制 IPAddressField(Field) - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制 GenericIPAddressField(Field) - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6 - 参数: protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6" unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启此功能,需要protocol="both" URLField(CharField) - 字符串类型,Django Admin以及ModelForm中提供验证 URL SlugField(CharField) - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号) CommaSeparatedIntegerField(CharField) - 字符串类型,格式必须为逗号分割的数字 UUIDField(Field) - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证 FilePathField(Field) - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能 - 参数: path, 文件夹路径 match=None, 正则匹配 recursive=False, 递归下面的文件夹 allow_files=True, 允许文件 allow_folders=False, 允许文件夹 FileField(Field) - 字符串,路径保存在数据库,文件上传到指定目录 - 参数: upload_to = "" 上传文件的保存路径 storage = None 存储组件,默认django.core.files.storage.FileSystemStorage ImageField(FileField) - 字符串,路径保存在数据库,文件上传到指定目录 - 参数: upload_to = "" 上传文件的保存路径 storage = None 存储组件,默认django.core.files.storage.FileSystemStorage width_field=None, 上传图片的高度保存的数据库字段名(字符串) height_field=None 上传图片的宽度保存的数据库字段名(字符串) DateTimeField(DateField) - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] DateField(DateTimeCheckMixin, Field) - 日期格式 YYYY-MM-DD TimeField(DateTimeCheckMixin, Field) - 时间格式 HH:MM[:ss[.uuuuuu]] DurationField(Field) - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型 FloatField(Field) - 浮点型 DecimalField(Field) - 10进制小数 - 参数: max_digits,小数总长度 decimal_places,小数位长度 BinaryField(Field) - 二进制类型
常用参数:
null : 数据库可为空
blank :数据校验时可为空
default : 默认值
unique : 唯一约束
verbose_name : 中文提示
choices : 可选择的数据
from django.db import models # Create your models here. class Person(models.Model): pid = models.AutoField(primary_key=True) name = models.CharField(max_length=32,db_column="username",unique=True,verbose_name="姓名") age = models.IntegerField(null=True,blank=True,verbose_name="年龄") birth = models.DateTimeField(auto_now_add=True) gender = models.IntegerField(choices=[(0,"男"),(1,"女")],default=0) choices里面需要放一个可迭代对象,第一个是数据库存放的数据 第二个是admin界面显示
字段参数
null 数据库中字段是否可以为空 db_column 数据库中字段的列名 default 数据库中字段的默认值 primary_key 数据库中字段是否为主键 db_index 数据库中字段是否可以建立索引 unique 数据库中字段是否可以建立唯一索引 unique_for_date 数据库中字段【日期】部分是否可以建立唯一索引 unique_for_month 数据库中字段【月】部分是否可以建立唯一索引 unique_for_year 数据库中字段【年】部分是否可以建立唯一索引 verbose_name Admin中显示的字段名称 blank Admin中是否允许用户输入为空 editable Admin中是否可以编辑 help_text Admin中该字段的提示信息 choices Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作 如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1) error_messages 自定义错误信息(字典类型),从而定制想要显示的错误信息; 字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date 如:{'null': "不能为空.", 'invalid': '格式错误'} validators 自定义错误验证(列表类型),从而定制想要的验证规则 from django.core.validators import RegexValidator from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\ MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator 如: test = models.CharField( max_length=32, error_messages={ 'c1': '优先错信息1', 'c2': '优先错信息2', 'c3': '优先错信息3', }, validators=[ RegexValidator(regex='root_\d+', message='错误了', code='c1'), RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'), EmailValidator(message='又错误了', code='c3'), ] )
注册django自带的admin管理控制台
在app01下的admin里面写注册 from django.contrib import admin from app01 import models # Register your models here. admin.site.register(models.Person)
启动项目
创建超级用户
python manage.py createsuperuser
Model Meta给表做上相应的参数
不是很常用 class UserInfo(models.Model): nid = models.AutoField(primary_key=True) username = models.CharField(max_length=32) class Meta: # 数据库中生成的表名称 默认 app名称 + 下划线 + 类名 db_table = "table_name" # admin中显示的表名称 verbose_name = '个人信息' # verbose_name加s verbose_name_plural = '所有用户信息' # 联合索引 index_together = [ ("pub_date", "deadline"), # 应为两个存在的字段 ] # 联合唯一索引 unique_together = (("driver", "restaurant"),) # 应为两个存在的字段
2.必知必会13条
import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day16.settings") import django django.setup() from app01 import models #all() 查询所有数据 [对象] 对象列表 queryset ret = models.Person.objects.all() #filter()查询满足条件的对象 ret = models.Person.objects.filter(name='ivy') #get 获取一个满足条件的对象,查不到会报错 查到大于1个的结果也会报错 # ret = models.Person.objects.get(name='ivy') #exclude 查询不满足条件的所有对象 ret = models.Person.objects.exclude(age=18) #不填字段名values 获取对象的字段名和值 [{}] queryset #填字段名 获取对象指定字段名和值 ret = models.Person.objects.all().values('pid','name') #不填字段名values 获取对象的字段名和值 [()] queryset #填字段名 获取对象指定字段名和值 ret = models.Person.objects.all().values_list('pid','name') #排序 order_by [对象] queryset 默认升序 -j降序 ret = models.Person.objects.all().order_by('pid','-age') #reverse 对已经排序的结果进行倒序 ret = models.Person.objects.all().order_by('pid').reverse() #distince 不能针对字段名去重,除非两条数据完全一致 ret = models.Person.objects.values('age').distinct() #查询结果的数据 是.all ret = models.Person.objects.count() #first 获取查询结果中的第一个对象 ret = models.Person.objects.first() #last() 获取结果中的最后一个对象 没有就返回none ret = models.Person.objects.last() #查看是否存在 ret = models.Person.objects.filter(name='ivy').exists() print(ret) #返回是对象列表 all() filter() exclude() values() values_list() order_by() reverse() distinct() 返回对象 get() first() last() 返回数字的 count 返回布尔值 exists()
知识点补充:类中打印对象的时候会调用__str__和__repr方法,如果没有str就调用repr
脚本的方式执行orm的操作
加载项目中所有环境 import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day16.settings") import django django.setup()
3.单标双下划线
import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day16.settings") import django django.setup() from app01 import models #查询大于1 ret = models.Person.objects.filter(pid__gt=1) #查询小于1 ret = models.Person.objects.filter(pid__gt=1) #查询大于等于1 ret = models.Person.objects.filter(pid__gte=1) #查询小于等于1 ret = models.Person.objects.filter(pid__lte=1) #查询1或3 ret = models.Person.objects.filter(pid__in=[1,3]) #查询大于等于1 小于等于3 ret = models.Person.objects.filter(pid__range=[1,3]) #模糊查询不忽略 ret = models.Person.objects.filter(name__contains='ivy') #忽略大小写 ret = models.Person.objects.filter(name__contains='ivy') #以什么开头 ret = models.Person.objects.filter(name__startswith='ivy') #以什么结尾 ret = models.Person.objects.filter(name__endswith='ivy') #打印age字段为空的数据,False表示不为空的数据 ret = models.Person.objects.filter(age__isnull=True) #打印年份是2019的数据 ret = models.Person.objects.filter(birth__year=2019) ret = models.Person.objects.filter(birth__contains='2019-07') print(ret)
4.外键的查询
正向查询 根据外键查piblisher 创建表的数据 class Publisher(models.Model): name = models.CharField(max_length=32) def __str__(self): return self.name class Book(models.Model): name = models.CharField(max_length=32) pub = models.ForeignKey(Publisher,on_delete=models.CASCADE) def __str__(self): return self.name 查询语句 import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day16.settings") import django django.setup() from app01 import models #基于对象的查询 book_obj = models.Book.objects.all() print(book_obj.pub)
#反向查询 #关系型管理对象 #从少的那边查多的通过关系型管理对象 小写表名_set pub_obj = models.Publisher.objects.first() print(pub_obj.book_set.all())
#基于字段查询 #这里的__表示跨表 ret = models.Book.objects.filter(pub__name='沙河出版社1') ret = models.Publisher.objects.filter(book__name="沙河小王子") print(ret)
创建表是添加related_name 属性 查询的时候 表名_set 直接换成related_name定义的值 class Publisher(models.Model): name = models.CharField(max_length=32) def __str__(self): return self.name class Book(models.Model): name = models.CharField(max_length=32) pub = models.ForeignKey(Publisher,on_delete=models.CASCADE,related_name="books") def __str__(self): return self.name #反向查询 #关系型管理对象 pub_obj = models.Publisher.objects.first() # print(pub_obj.books.all()) #基于字段查询 #这里的__表示跨表 ret = models.Publisher.objects.filter(books__name="沙河小王子") print(ret)
创建表是指定related_query_name 查询的时候需要使用指定的这个值 class Publisher(models.Model): name = models.CharField(max_length=32) def __str__(self): return self.name class Book(models.Model): name = models.CharField(max_length=32) pub = models.ForeignKey(Publisher,on_delete=models.CASCADE,related_name="books",related_query_name="xx") def __str__(self): return self.name 查询 ret = models.Publisher.objects.filter(xx__name="沙河小王子") print(ret)
知识点补充:配置多数据库
直接添加对应的数据库连接信息 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'day16', 'HOST':"127.0.0.1", "PORT":3306, "USER":'root', "PASSWORD":'wang', }, 'db2': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'day16', 'HOST': "127.0.0.1", "PORT": 3306, "USER": 'root', "PASSWORD": 'wang', } } 区分使用哪个表 ret = models.Person.objects.using('db2').filter(birth__contains='2019-07') 使用using('表名')
5.多对多的操作
创建book和author表多对多的关系 class Book(models.Model): name = models.CharField(max_length=32) pub = models.ForeignKey(Publisher,on_delete=models.CASCADE,related_name="books",related_query_name="xx") def __str__(self): return self.name class Author(models.Model): name = models.CharField(max_length=32) books = models.ManyToManyField('Book') #写上这个字段 django会自动创建第三张表来描述author和book之间的关系
#多对多查询 #查询某个作者出的书 import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day16.settings") import django django.setup() from app01 import models author_obj = models.Author.objects.first() print(author_obj) print(author_obj.name) print(author_obj.books.all())
通过book查作者
book_obj = models.Book.objects.first()
print(book_obj.author_set.all())
通过字段查找
ret = models.Author.objects.filter(books__name="沙河小王子")
print(ret)
多对多常见方法 #set()设置多对多关系 #如果数据库有数据相当于重置 #设置1,2表示这两本书和作者的关系 可以写[id] [对象] author_obj.books.set([1,2]) author_obj.books.set(models.Book.objects.filter(id__in=[1,3,5])) #add()添加多对多的关系 [id] [对象] author_obj.books.add(2) #拿到的是一个queryset 需要用*号打散 author_obj.books.add(*models.Book.objects.filter(id=4)) #remove()删除 操作跟add一样 author_obj.books.remove(*models.Book.objects.filter(id=4)) #clear()删除所有多对多的关系 author_obj.books.clear() #create 通过作者创建一本书,然后在把书和作者之间关联起来 author_obj.books.create(name="hongloumeng",pub_id=1) 知识点补充:外键也有以上这些方法 but 外键不能使用id 以及使用clear的使用外键关系那里必须设置null=True
6.聚合和分组
分组和聚合 import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day16.settings") import django django.setup()
#聚合aggragate from app01 import models from django.db.models import Max,Min,Sum,Avg,Count ret = models.Book.objects.all().aggregate(Sum('price')) ret = models.Book.objects.all().aggregate(sum=Sum('price')) #分组annotate #统计每一本书的作者个数 ret = models.Book.objects.annotate(Count('author')).values() #统计出每个出版社卖的最便宜的数的价格 #方法一 ret = models.Publisher.objects.annotate(Min('xx__price')).values() #方法二 annotate前的values中的字段就是条件分组 annotate后不再用values ret = models.Book.objects.values('pub__name').annotate(Min('price')) #统计不止一个作者的图书 models.Book.objects.annotate(count=Count('author')).filter(count__gt=1) #查询各个作者出的书的总价格 ret = models.Author.objects.annotate(Sum('books__price')).values() print(ret)
7. F、Q、事件
Django 提供 F()对两个字段的值做比较
import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day16.settings") import django django.setup() from app01 import models from django.db.models import F ret =models.Book.objects.filter(sale__gt=F('store')).values() #使用update来更新 obj = models.Book.objects.update(sale=F('sale')*2+13)
filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR语句),你可以使用Q对象
与或非的使用需要导入Q import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day16.settings") import django django.setup() from app01 import models from django.db.models import F,Q # |表示并且的关系 & 与 ~ 非 默认逗号表示与 ret = models.Book.objects.filter(Q(id__gt=4)| Q(id__it=2)) print(ret)
知识点补充:事务操作
import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day16.settings") import django django.setup() from app01 import models from django.db import transaction try: with transaction.atomic(): #写具体的操作 models.Publisher.objects.create(name='xxxx') except Exception as e: print(e)
知识点补充django终端打印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', }, } }
二、cookie和session
cookie是保存在浏览器上的一组组键值对,由服务器让浏览器进行设置,下次自动携带相应
的cookie去访问服务器
cookie的工作原理是:由服务器产生内容,浏览器收到请求后保存在本地;当浏览器再次访问时,浏览器会自动带上Cookie,这样服务器就能通过Cookie的内容来判断这个是“谁”了。
参数:
- key, 键
- value='', 值
- max_age=None, 超时时间
- expires=None, 超时时间(IE requires expires, so set it if hasn't been already.)
- path='/', Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
- domain=None, Cookie生效的域名
- secure=False, https传输
- httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
设置cookie方法一
from django.shortcuts import render,HttpResponse,redirect # Create your views here. def login(request): print(request.method) if request.method == "POST": username = request.POST.get("username") password = request.POST.get("password") if username == 'ivy' and password == '123': #登录成功设置cookie ret = redirect('/index/') ret.set_cookie('is_login','1') return ret return render(request,'login.html') def index(request): is_login = request.COOKIES.get('is_login') if is_login != "1": return redirect('/login/') return HttpResponse("登录ok")
通过装饰器获取cookie完整版
from django.shortcuts import render,HttpResponse,redirect # Create your views here. def login_required(func): def inner(request,*args,**kwargs): is_login = request.COOKIES.get('is_login') if is_login != "1": return_url = request.path_info return redirect('/login/?return_url'.format(return_url)) #登录成功 ret = func(request,*args,**kwargs) return ret return inner def login(request): print(request.method) if request.method == "POST": username = request.POST.get("username") password = request.POST.get("password") if username == 'ivy' and password == '123': #登录成功设置cookie return_url = request.GET.get('return_url') if return_url: ret = redirect(return_url) else: ret = redirect('/index/') ret.set_cookie('is_login','1') return ret return render(request,'login.html') @login_required def index(request): return HttpResponse("登录ok")
删除cookie
def logout(request): ret = redirect('/login/') ret.delete_cookie('is_login') return ret
通过get_signed_cookie加盐设置cookie
from django.shortcuts import render,HttpResponse,redirect # Create your views here. def login_required(func): def inner(request,*args,**kwargs): # is_login = request.COOKIES.get('is_login') is_login = request.get_signed_cookie('islogin',default='',salt='s26') if is_login != "1": return_url = request.path_info return redirect('/login/?return_url'.format(return_url)) #登录成功 ret = func(request,*args,**kwargs) return ret return inner def login(request): print(request.method) if request.method == "POST": username = request.POST.get("username") password = request.POST.get("password") if username == 'ivy' and password == '123': #登录成功设置cookie return_url = request.GET.get('return_url') if return_url: ret = redirect(return_url) else: ret = redirect('/index/') # ret.set_cookie('is_login','1') ret.set_signed_cookie('islogin','1','s26') return ret return render(request,'login.html') @login_required def index(request): return HttpResponse("登录ok") def logout(request): ret = redirect('/login/') ret.delete_cookie('is_login') return ret
get_signed_cookie方法的参数:
- default: 默认值
- salt: 加密盐
- max_age: 后台控制过期时间
session
保存在服务器上的一组组键值对,必须依赖cookie
工作原理:浏览器第一次登陆的时候没有cookie 走到服务器登陆成功以后服务器会找一个地方存放cookie信息,然后生成一个唯一的表示区分是哪个用户的,再把标识发送给浏览器下次浏览器会带上标识去服务器,如果服务器有对应信息才能访问。
设置session
from django.shortcuts import render,HttpResponse,redirect # Create your views here. def login_required(func): def inner(request,*args,**kwargs): # is_login = request.COOKIES.get('is_login') # is_login = request.get_signed_cookie('islogin',default='',salt='s26') is_login = request.session.get('is_login') if is_login != "1": return_url = request.path_info return redirect('/login/?return_url'.format(return_url)) #登录成功 ret = func(request,*args,**kwargs) return ret return inner def login(request): print(request.method) if request.method == "POST": username = request.POST.get("username") password = request.POST.get("password") if username == 'ivy' and password == '123': #登录成功设置cookie return_url = request.GET.get('return_url') if return_url: ret = redirect(return_url) else: ret = redirect('/index/') # ret.set_cookie('is_login','1') # ret.set_signed_cookie('islogin','1','s26') request.session['is_login'] = '1' return ret return render(request,'login.html') @login_required def index(request): return HttpResponse("登录ok") def logout(request): ret = redirect('/login/') # ret.delete_cookie('is_login') #方法一 request.session.pop('is_login') #方法二 request.session.delete() #删除整个session数据 不删除cookie #方法三 request.session.flush() #删除数据库里面保存的以及cookit return ret from django.conf import global_settings