Python全栈之路-Django(十)
1 ORM补充
1.1 select_related & prefetch_related
from app01 import models
def test(request):
# select_related 自动关联UserType表(inner join),可以关联多个
q = models.UserInfo.objects.all().select_related('ut',)
for row in q:
print(row.name, row.ut.title)
# prefetch_related 通过多次单表查询解决连表查询效率低的问题
# select * from userinfo;
# Django内部:select * from usertype where id in [1,2,3]
# Django将两个结果集整合在一起
q = models.UserInfo.objects.all().prefetch_related('ut', )
for row in q:
print(row.name, row.ut.title)
return HttpResponse('...')
1.2 多对多操作
app01.models.py
class Boy(models.Model):
name = models.CharField(max_length=32)
m = models.ManyToManyField('Girl') # 多对多
class Girl(models.Model):
nick = models.CharField(max_length=32)
# class Love(models.Model):
# b = models.ForeignKey('Boy')
# g = models.ForeignKey('Girl')
# class Meta:
# unique_together = [ # 联合唯一索引
# ('b', 'g')
# ]
app01.views.py
# 数据库操作
from app01 import models
def test(request):
# # select_related 自动关联UserType表(inner join),可以关联多个
# q = models.UserInfo.objects.all().select_related('ut',)
# for row in q:
# print(row.name, row.ut.title)
# # prefetch_related 通过多次单表查询解决连表查询效率低的问题
# # select * from userinfo;
# # Django内部:select * from usertype where id in [1,2,3]
# # Django将两个结果集整合在一起
# q = models.UserInfo.objects.all().prefetch_related('ut', )
# for row in q:
# print(row.name, row.ut.title)
# 多对多
# objs1 = [
# models.Boy(name='温艳杰'),
# models.Boy(name='杨振威'),
# models.Boy(name='苏浩智'),
# models.Boy(name='邹润成'),
# ]
# models.Boy.objects.bulk_create(objs1, 10)
# objs2 = [
# models.Girl(nick='李智'),
# models.Girl(nick='韩星宇'),
# models.Girl(nick='秦镇'),
# models.Girl(nick='杨涵'),
# ]
# models.Girl.objects.bulk_create(objs2, 10)
# models.Love.objects.create(b_id=1, g_id=1)
# models.Love.objects.create(b_id=1, g_id=2)
# models.Love.objects.create(b_id=2, g_id=4)
# models.Love.objects.create(b_id=2, g_id=3)
# models.Love.objects.create(b_id=3, g_id=3)
# models.Love.objects.create(b_id=4, g_id=4)
# models.Love.objects.create(b_id=4, g_id=2)
# 1 和温艳杰有关联的姑娘的列表
# 方法1:先找到该对象,然后通过反向操作获取girl相关信息
# obj = models.Boy.objects.filter(name='温艳杰').first()
# love_list = obj.love_set.all()
# for row in love_list:
# print(row.g.nick)
# 方法2: 遍历时跨表
# love_list = models.Love.objects.filter(b__name='温艳杰')
# for row in love_list:
# print(row.g.nick)
# 方法3:values values_list
# love_list = models.Love.objects.filter(b__name='温艳杰').values('g__nick')
# for item in love_list:
# print(item['g__nick'])
# love_list = models.Love.objects.filter(b__name='温艳杰').values_list('g__nick')
# for item in love_list:
# print(item[0])
# 方法4:select_related
# love_list = models.Love.objects.filter(b__name='温艳杰').select_related('g')
# for obj in love_list:
# print(obj.g.nick)
# 2 查看和韩星宇有关系的男生
# 方法1:
# obj = models.Girl.objects.filter(nick='韩星宇').first()
# love_list = obj.love_set.all()
# for row in love_list:
# print(row.b.name)
# 方法2:
# love_list = models.Love.objects.filter(g__nick='韩星宇')
# for row in love_list:
# print(row.b.name)
# 方法3:
# love_list = models.Love.objects.filter(g__nick='韩星宇').values('b__name')
# for item in love_list:
# print(item['b__name'])
# love_list = models.Love.objects.filter(g__nick='韩星宇').values_list('b__name')
# for item in love_list:
# print(item[0])
# 方法4:
# love_list = models.Love.objects.filter(g__nick='韩星宇').select_related('b')
# for obj in love_list:
# print(obj.b.name)
#
# ManyToManyField 会生成app01_boy_m表,即boy和girl关系表
# 正向操作
obj = models.Boy.objects.filter(name='温艳杰').first()
print(obj.id, obj.name)
# 往app01_boy_m添加与obj对象有关系的列
# obj.m.add(3) # 单值
# obj.m.add(2, 4) # 多值
# obj.m.add(*[1,]) # 列表
# 在关系表中删除与obj对象有关系的列
# obj.m.remove(1)
# obj.m.remove(2, 4)
# obj.m.remove(*[3])
# 重置
# obj.m.set([3, 1, ])
# 获取与obj有关系的女孩列表
girl_list = obj.m.all().filter(nick='李智') # q是girl对象
for item in girl_list:
print(item.nick)
# 在关系表中删除所有与obj有关系的列
# obj.m.clear()
# 反向操作:
obj = models.Girl.objects.filter(nick='韩星宇').first()
print(obj.id, obj.nick)
v = obj.boy_set.all() # boy对象
print(v)
return HttpResponse('...')
2 CSRF
给用户生成一段随机字符串,用户提交数据时需要携带,否则返回403状态码,用于防范XSS攻击
<form action="/csrf1.html" method="post">
{% csrf_token %}
<input type="text">
<input type="submit" value="提交">
</form>
不仅会写到form表单里,cookie里也会写入
全站禁用
# 'django.middleware.csrf.CsrfViewMiddleware',
局部禁用
from django.views.decorators.csrf import csrf_exempt,csrf_protect
@csrf_exempt # 局部禁用
def csrf1(request):
if request.method == 'GET':
return render(request, 'csrf1.html')
else:
return HttpResponse('...')
局部应用:
from django.views.decorators.csrf import csrf_exempt,csrf_protect
@csrf_protect # 局部使用
def csrf1(request):
if request.method == 'GET':
return render(request, 'csrf1.html')
else:
return HttpResponse('...')
2.1 ajax提交数据时携带CSRF
方法1:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/csrf1.html" method="post">
{% csrf_token %}
<input type="text" id="user">
<input type="submit" value="提交">
<input type="button" value="Ajax提交" onclick="submitForm();">
</form>
<script src="/static/jquery-3.2.1.min.js"></script>
<script>
function submitForm() {
var csrf = $('input[name=csrfmiddlewaretoken]').val();
var user = $('#user').val();
$.ajax({
url:'csrf1.html',
type: 'POST',
data: {'user': user, 'csrfmiddlewaretoken': csrf},
success:function (arg) {
console.log(arg)
}
})
}
</script>
</body>
</html>
方法2:
function submitForm() {
var token = $.cookie('csrftoken')
var user = $('#user').val();
$.ajax({
url:'csrf1.html',
type: 'POST',
headers:{'X-CSRFToken': token},
data: {'user': user},
success:function (arg) {
console.log(arg)
}
})
}
3 CBV补充
CBV应用装饰器(注:对于CSRF目前只能在类上加装饰器)
# 1.类上加装饰器
@method_decorator(csrf_exempt,name='dispatch')
class Foo1(View):
def get(self,request):
pass
def post(self,request):
pass
# 2.指定方法上加
class Foo2(View):
@method_decorator(wrapper)
def get(self,request):
pass
def post(self,request):
pass