ORM一对一
列子: 用户表(母表): id name age 1 zekai 18 薪水表(子表): id money us_id 1 2000 1 #1这个id只能出现一次 class UserInfo(models.Model): name = models.CharField(max_length=32) age = models.CharField(max_length=32) class Salary(models.Model): money = models.CharField(max_length=32) us = models.OneToOneField("UserInfo") 一对一: #增加: # models.UserInfo.objects.create(name='zekai', age=18) # 查询: # 正向查询(子表查母表): # 1.11.22版本 :res.us.name # 1.11.10版本 : res.母表表名小写.name res = models.Salary.objects.filter(money="3000").first() print(res.us.name) # 反向查询(母表查子表) # obj.子表小写.子表列名 res = models.UserInfo.objects.filter(name='zekai').first() print(res.salary.money)
Django列类型与参数
mysql django tinyint 无 smallint(unsigned) SmallIntegerField (PositiveSmallIntegerField) 括号里面表示无负号 数字 int (unsigned)) IntegerField (PositiveIntegerField) mediumint 无 bigint(unsigned) BigIntegerField 没有无负号单词 float FloatField decimal(5,2) : 200.23 DecimalField 小数点后面2位,总共5位 char 无 字符串 varchar CharFiled text TextField 时间 datetime (2019-7-17 12:23:34) DateTimeField date (2019-7-17) DateField - 参数: max_length=32 字符串最大长度 null=True : 可以设置为null db_index=True : 设置索引 default : 设置默认值 unique : 设置唯一索引 db_column: 在表中重新取一个名字 unique_together: 联合唯一索引 index_together : 普通联合索引 案例: class xxx(): 表模型类 class Meta: unique_together = ( ('money', 'us_id'), .... ) index_together = ( ('money', 'us_id') .... )
Django-admin列类型与参数
djagno-admin: django自带的管理后台系统 用户名、密码命令生成: python3 manage.py createsuperuser 如何管理自己生成的表: 每个app下admin文件中导入模型: from app01 import models admin.site.register(models.UserInfo) 下面都是在django-admin中生效 django-admin中的列类型: 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格式的验证 FileField(Field) djagno-admin中的参数 : verbose_name Admin中显示的字段名称 blank Admin中是否允许用户输入为空 editable Admin中是否可以隐藏 help_text Admin中该字段的提示信息 choices Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作 choices = ( (1, '男'), (2, '女') #1是mysql表现形式 男女是djagno-admin表现形式 ) gender = models.IntegerField(choices=chocies) from django.core.validators import RegexValidator test3 = models.CharField( max_length=32, error_messages={ #优先级,先c1再mes 'c1': '优先错信息1', 'c2': '优先错信息2', 'c3': '优先错信息3', }, validators=[RegexValidator(regex='root_d+', message='错误了', code='c1')] )
Django内置分页
def index(request): from django,core,paginator import Paginator,EmptyPage(用户点击页数超出页面总页面数,用万能异常能捕获到·) 1. 接收页数 try: cur_page = request.GET.get('cur_page') #接收的是用户点击的第几页 cur_page = int(cur_page) #强行报错 except Exception as e: cur_page = 1 user_list = models.UserInfo.objects.all() 2.拿到页数数据 paginator = Paginator(user_list, 10) #括号里边是(列表套对象,每页多少条数据) #paginator这个对象有下面这些方法: # per_page: 每页显示多少条数据 # count: 传过来数据总个数(多少条) # num_pages: 一共能显示多少页 # page_range: 一共能显示多少页索引范围,如: 索引范围是1到10 ,就是翻页能从1点到10 # page: 后面点page能获得page的方法,如下 3.发送到html users = paginator.page(cur_page) #参数是用户点击的第几页,而users就是用户点击的第几页的所有数据 #users的方法: # has_next 是否有下一页 # next_page_number 获取下一页页码 # has_previous 是否有上一页 # previous_page_number 获取上一页页码 # object_list 用户点击的第几页的数据列表 # number 当前页码 # paginator 又可以点paginator对象,获得paginator的方法 return render(request, "index.html", {"user_list":users}) 4.在html使用方法 #users传到html后,就可以在html点上面的所有方法
html代码:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Title</title> </head> <body> <ul> {% for user in user_list.object_list %} <li>{{ user.name }}</li> {% endfor %} </ul> {% if user_list.has_previous %} <a href="/index/?cur_page={{ user_list.previous_page_number }}">上一页</a> {% endif %} {% for num in user_list.paginator.page_range %} <a href="/index/?cur_page={{ num }}">{{ num }}</a> {% endfor %} {% if user_list.has_next %} <a href="/index/?cur_page={{ user_list.next_page_number }}">下一页</a> {% endif %} </body> </html>
手写分页
# 自定制的分页类 class PageInfo(): def __init__(self, cur_page, total, per_page=10, show_page=11): cur_page 用户点击的第多少页 total 表有多少条数据 per_page 每页多少条数据 show_page 显示当前页数一共为11页 try: self.cur_page = int(cur_page) except Exception as e: #如果传入不是数字强行报错 self.cur_page = 1 self.per_page = per_page self.show_page = show_page a, b = divmod(total, per_page) #前面整除的数字,后面是余数的数字(301,10)=>(30,1) if b: self.total_page = a + 1 #定义一个self.total_page(总页数) else: self.total_page = a def get_start(self): #切片的开始位置 return (self.cur_page - 1) * self.per_page def get_stop(self): #切片的接收位置 return self.cur_page * self.per_page def page(self): #拼接自己写好的html标签 half = int((self.show_page ) / 2) #为了区分点击两边的区域 if self.total_page < self.show_page: #要显示的页数小于要展示的页数show_page(数据太少) begin = 1 stop = self.total_page + 1 else: # 下面代码可以自定义,比如:begin = self.cur_page - half # 显示效果是左右越点越少 if self.cur_page - 1 < half: #靠最左边点击会出现负数的情况 begin = 1 stop = self.show_page + 1 elif self.cur_page + half > self.total_page: #靠最右边点击会出现超出页数的情况 begin = self.total_page - self.show_page + 1 stop = self.total_page + 1 else: #正常显示数据 begin = self.cur_page - half stop = self.cur_page + half + 1 sli = [] if self.cur_page == 1: #如果上一页一直点到第一页,在点会出现负数并报错,所以用#让它处在第一页 s = "<li class='disabled'><a href='#'>上一页</a></li>" else: s = "<li><a href='/custom/?cur_page=%s'>上一页</a></li>" %(self.cur_page - 1) #没有上述情况,就进行跳转 sli.append(s) for num in range(begin, stop): #为了显示高亮 if num == self.cur_page: s = "<li class='active'><a href='/custom/?cur_page=%s'>%s</a></li>" %(num, num) else: s = "<li><a href='/custom/?cur_page=%s'>%s</a></li>" %(num, num) sli.append(s) if self.cur_page == self.total_page: #作用同上一页一样 s = "<li class='disabled'><a href='#'>下一页</a></li>" else: s = "<li><a href='/custom/?cur_page=%s'>下一页</a></li>" % (self.cur_page + 1) sli.append(s) page_str = " ".join(sli) #在列表中,把逗号换成空,返回一个字符串 return page_str
# 自定制的分页函数
def custom(request):
cur_page = request.GET.get('cur_page') #用户点击的第几页(一开始需要自己来传)
total = models.UserInfo.objects.count()
pageinfo = PageInfo(cur_page, total)
start = pageinfo.get_start()
stop = pageinfo.get_stop()
user_list = models.UserInfo.objects.all()[start:stop]
return render(request, "custom.html",{"user_list":user_list, "pageinfo":pageinfo}) #将对象传入html,在html中可以使用点方法
#推导理论
cur_page start stop
1 0 10
2 10 20
3 20 30
n (n-1)*per_page n * per_page
html代码(需要bs引入):
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Title</title> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> </head> <body> <ul> {% for user in user_list %} <li>{{ user.name }}</li> {% endfor %} </ul> <nav aria-label="Page navigation"> <ul class="pagination"> {{ pageinfo.page | safe }} </ul> </nav> </body> </html>
CSRF:
跨站请求伪造
原理:在对方使用的浏览器上拿到对方的cookie,使用这个cookie进行对对方访问过的网站,进行访问和操作
造成原因:用户使用同一个浏览器打开两个网站,第一个网站状态还没有退出,
而第二个网站不受信用,如果在第二个网站进行操作,就有可能受到攻击
解决方案:浏览器在请求服务器的时候,服务器除了返回数据和cookie,还在返回了token,
而tokin放在发的html中的form表单,下次再次访问,会和服务器存的token进行比对,不一样拒绝访问
不同之处:tokin一般获取不到,而cookie可以,并且tokin要先于cookie传入浏览器
中间件开启的时候,表示开启全局的csrf验证(token验证): HTML处理方法 1. 在form表单中生成cookie <form> {% csrf_token %} 在form表单中生成cookie <input type='text'> </form> FBV处理方法 1..下面函数关闭csrf验证 from django.views.decorators.csrf import csrf_exempt @csrf_exempt def csrf1(request): if request.method == 'GET': return render(request, 'csrf1.html') else: return HttpResponse('ok') 当中间件关闭的时候: 1.下面函数开启csrf验证 from django.views.decorators.csrf import csrf_protect @csrf_protect def csrf1(request): if request.method == 'GET': return render(request, 'csrf1.html') else: return HttpResponse('ok') CBV处理方法: from django.utils.decorators import method_decorator @method_decorator(csrf_protect, name='get') #里面第一个是上述开启或关闭方法,第二个是对哪个请求有作用,也可以不写 class User(View): def get(self, request): pass def post(self, request): pass ajax处理方法: csrftoken = $('input[name="csrfmiddlewaretoken"]').val() #属性选择器 $.ajax({ type:"POST", url : '/xxxx/', data: {"name":'xxxx'}, headers : {'X-CSRFToken': token}, #自己获取表单的token,放进去发送 success: function(){ console.log(data) } })