csrf的相关装饰器
1.csrf的相关装饰器与csrf验证相关
2.当我们把scrf的中间件打开之后,我们的方法都需要验证
3.打开csrf的中间件,有几个方法不验证--->csrf_exemp
4.关闭csrf的中间件之后,有几个方法要验证--->csrf_protect
5.模块:from django.views.decorators.csrf import csrf_protect,csrf_exemp
FBV
局部禁用:用装饰器(在FBV中使用)
需求:注释scrf中间件,让func方法经过验证----->导模块:from django.views.decorators.csrf import csrf_protect
from django.shortcuts import render
from django.views.decorators.csrf import csrf_protect
@csrf_protect
def func(request):
return render(request,'func.html')
需求:打开scrf中间件,让func方法不经过验证----->导模块:from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def func(request):
return render(request,'func.html')
CBV
需求:让Login不验证---->导模块
第一种方式添加装饰器不可行
from django.views import View
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt,csrf_protect
class Login(View):
def get(self,request):
print('get')
return HttpResponse('get')
@method_decorator(csrf_exempt)
def post(self,request):
print('post')
return HttpResponse('post')
第二种方式添加装饰器不可行
from django.views import View
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt,csrf_protect
# @method_decorator(csrf_exempt,name='post')
class Login(View):
def get(self,request):
print('get')
return HttpResponse('get')
def post(self,request):
print('post')
return HttpResponse('post')
第三种方法可行
from django.views import View
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt,csrf_protect
class Login(View):
@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
return super(Login, self).dispatch(request, *args, **kwargs)
def get(self,request):
print('get')
return HttpResponse('get')
def post(self,request):
print('post')
return HttpResponse('post')
from django.views import View
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt,csrf_protect
@method_decorator(csrf_exempt,name='dispatch')
class Login(View):
def get(self,request):
print('get')
return HttpResponse('get')
def post(self,request):
print('post')
return HttpResponse('post')
总结: 1.CBV的csrf装饰器,只能加载类上(指定方法为dispatch)和dispatch方法上(django的bug)
2.给get方法使用csrf_token检测
Auth模块
1.Auth模块:是Django自带的用户认证模块
1.我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统。此时我们需要实现包括用户注册、用户登录、用户认证、注销、修改密码等功能,这是个麻烦的事情。
2.Django作为一个完美主义者的终极框架,当然也会想到用户的这些痛点。它内置了强大的用户认证系统–auth,它默认使用 auth_user 表来存储用户数据。
2.django自带的后台管理系统依赖的就是auth_user表,要想登陆django的后台管理系统,就需要创建一个超级用户
创建超级用户步骤:
1.终端输入:pthon manage.py createsuperuser
2.输入用户、邮箱、password(echoed打印)
3.再输入一次密码
4.成功
ps:django_migrations --->里面的数据是有关下面应用的记录
"""
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01'
]
"""
用户登录
1.比较用户名和密码
1. 去哪个表里查询数据------>auth_user表
2. 密码如何比较
解决:借助于auth模块
1.导模块:from django.contrib import auth
2.比较数据:user_obj=auth.authenticate(request,username=user,password=pwd)
ps:返回的是用户对象,当用户不存在的时候,返回的是false
2.保存用户信息
1.使用session--->request.session['username'] = user_obj.username
2.使用auth.login--->auth.login(request,用户对象)
ps:如果你用了auth,就用一整套。只要你用了auth.login方法,后续就可以在任何方法里面通过:request.user拿到用户对象。eg:request.user.username --->user_obj.username
from django.contrib import auth
def login(request):
if request.method == 'POST':
# print(request.POST)
user = request.POST.get('username')
pwd = request.POST.get('password')
# 比对数据
user_obj = auth.authenticate(request,username=user,password=pwd)
# print(user_obj) # nana __str__
# print(user_obj.username) # nana
if user_obj:
# 保存用户的信息
# 1.request.session['username'] = user_obj.username
# 2.auth.login(request,user_obj)
auth.login(request,user_obj)
return redirect('/home/')
return HttpResponse('用户名或密码错误')
return render(request,'login.html')
def home(request):
return render(request,'home.html')
用户认证
需求:登陆成功后才能访问home
1.如何判断用户是否登录了
1.1 session request.session.get('username')
1.2 auth模块:request.user.is_authenticated()-->True,False
ps:request.user.is_authenticated()在django1中加括号,在django2中不加括号
2.认证装饰器
1.1 导模块:from django.contrib.auth.decorators import login_required
1.2 装饰器:@login_required(),默认提交:/account/login/
1.局部添加:@login_required(login_url ='/xxx/')-->未登陆跳转/xxx/
2.全局添加:@login_required()-->在配置文件中加:LOGIN_URL = '/login/',未登陆跳转
def home(request):
# 1.需求:登陆成功后才能访问home页面
# 1.1 session request.session.get('username')
# 1.2 auth模块:request.user.is_authenticated()
print(request.user.is_authenticated()) # True
if request.user.is_authenticated():
return render(request,'home.html')
return redirect('/login/')
from django.contrib.auth.decorators import login_required
@login_required(login_url='/xxxx/') # 局部添加
def home(request):
return render(request,'home.html')
@login_required # 全局添加,在配置文件中加:LOGIN_URL = '/login/',未登陆跳转
def index(request):
return HttpResponse('index')
修改密码
1.验证老密码:request.user.check_password(旧密码) --->True,False
2.修改密码:
1.request.user.set_password(新密码)-->这一句没有真正的操作数据库(update)
2.request.user.save()-->真正的操作数据库(update)
3.request.user-->返回的是用户对象;如果返回的是AnonymousUser,就是匿名用户,未登陆
@login_required
def set_password(request):
print(request.user) # AnonymousUser 匿名用户 nana
if request.method == 'POST':
print(request.POST.get('username')) # None 禁用
print(request.POST.get('password')) # 123
# 1.验证老密码是否正确
old_pwd = request.POST.get('old_password')
is_right = request.user.check_password(old_pwd)
print(is_right)
if not is_right:
return HttpResponse('原密码错误')
# 2.先判断两次密码是否一致
new_pwd = request.POST.get('new_password')
if old_pwd == new_pwd:
return HttpResponse('新密码不能和旧密码一致')
# 3.验证新密码和第三次输入的密码是否一致
confirm_pwd = request.POST.get('confirm_password')
if new_pwd != confirm_pwd:
return HttpResponse('两次密码不一致')
# 4.修改密码
request.user.set_password(new_pwd) # 这一句没有真正的操作数据库(update)
request.user.save() # 真正的操作数据库(update)
return HttpResponse('修改成功')
return render(request,'set_password.html',locals())
注销登录
1.注销用户:
1.导模块:from django.contrib import auth
2.注销用户:auth.logout(request)
2.当调用该函数时,当前请求的session信息会全部清除
from django.contrib.auth import logout
def logout(request):
auth.logout(request) # request.session.flush
return redirect('/home/')
注册用户
1.导模块:from django.contrib.auth.models import User
2.注册用户名密码
创建不加密:creat()-->User.objects.create(username=username,password=password)
创建加密的:creat_user()-->User.objects.create_user(username=username,password=password)
创建超级用户:create_superuser() --> User.objects.create_superuser(username=username,email='123@qq.com',password=password # 邮箱必须填
from django.contrib.auth.models import User
def register(request):
if request.method =='POST':
username = request.POST.get('username')
password = request.POST.get('password')
# 方法1:创建普通用户(密码不加密)
# User.objects.create(username=username,password=password) # 不加密
# 方法2:创建普通用户(密码加密)
# User.objects.create_user(username=username,password=password) # 加密
# 方法3:创建超级用户
User.objects.create_superuser(username=username,email='123@qq.com',password=password) # 加密
return redirect('/home/')
return render(request,'register.html')
方法总结
https://www.yuque.com/liyangqit/lb35ya/mmq0y5
扩展默认的auth_user表
1.由于auth_user表是django创建的,后续我们有扩展字段的需求,所以我们对这张表进行扩展
2.如何扩展
1.在models.py写类,建表
2.扩展auth_user表,就必须继承AbstractUser类,不再继承models.Model;导模块:from django.contrib.auth.models import AbstractUser
3.我们在扩展字段的时候,默认的字段我们不要动,只写我们要增加的字段
ps:
1. 扩展字段的时候,默认的字段不要动,只写自己要增加的字段
2. 如果扩展了这张表,那么,auth_user表就不存在了,有的是我们自己新建的这张表
3. 新建出来的这张表里面的字段,有之前auth_user表的所有字段加自己添加的字段
4. 需要在配置文件中添加一个变量,告诉django我要用现在新的表替代原来的auth_user表
AUTH_USER_MODEL = '应用名.类名'
eg:AUTH_USER_MODEL = 'app01.UserInfo'
5. 如果在扩展这张表之前已经执行了数据库迁移命令,需要从新换库
6. 如果你已经迁移了,还想扩展,怎么办?
1. 换库(应用下的migration删除)
2. 删所有应用下的migrations和django自动创建的migrantion表数据
7. 得出结论:在执行迁移命令之前就扩展好(应用下的migration删除)
from django.db import models
from django.contrib.auth.models import AbstractUser
class aaa(AbstractUser):
phone = models.CharField(max_length=64)
avatar = models.CharField(max_length=64)
test = models.CharField(max_length=64)
# settings.py
AUTH_USER_MODEL = 'app01.aaa'
import os
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django12.settings")
import django
django.setup()
from app01 import models
fields = models.aaa._meta.fields
l1 = []
for field in fields:
print(field.name)
l1.append(field.name)
print(l1) # ['id', 'password', 'last_login', 'is_superuser', 'username', 'first_name', 'last_name', 'email', 'is_staff', 'is_active', 'date_joined', 'phone', 'avatar', 'test']
BBS
1.对于任何一个项目来说,最终的是不是业务逻辑,而是表结构的设计,以及表关系的设计
我们以后拿到一个新的需求的时候,我们首先考虑的是表结构和表关系
表关系
分析BBS需要哪些表以及表与表之间的关系!!!
1. 用户表
扩展auth_user表
扩展字段:
phone
avatar
create_time
...
# 表关系
和站点表是一对一的关系
2. 站点表
site_name 站点名称
site_title 站点标题
site_style 站点样式
3. 文章表
title 文章标题
desc 文章摘要
content 文章内容
create_time 文章发表的时间
# 数据库字段设计优化
up_num = models.BigIntegerField(verbose_name='点赞数',default=0)
down_num = models.BigIntegerField(verbose_name='点踩数',default=0)
comment_num = models.BigIntegerField(verbose_name='评论数',default=0)
# 表关系
文章和标签是多对多的关系
文章和分类表是一对多的关系
站点表和文章表是一对多的关系
4. 文章标签表
标签名称
# 表关系
标签表和站点表是一对多的关系
5. 分类表
分类名称
# 表关系
分类表和站点表是一对多的关系
6. 点赞点踩表
ps:谁在什么时间点赞了哪篇文章
user
article
is_up
create_time
7. 评论表comment
ps:谁在什么时间给哪篇文章评论了什么内容
user
artilce
content
create_time
ps: 1.根评论和子评论的概念
根评论:评论文章的评论
子评论:评论文章的评论的评论
根评论和子评论:一对多
eg: 1. PHP是世界上最好的语言
1.1 python是最好的
1.2 java是最好的额
"""
id user article content creare_time parent_id
1 1 1 a ''
2 2 1 b '' 1
3 3 1 c '' 2
parent = models.ForeignKey(to='comment')
parent = models.ForeignKey(to='self') # 自关联
"""
表结构
from django.db import models
# Create your models here.
"""
先写普通字段
之后再写外键字段
"""
from django.contrib.auth.models import AbstractUser
class UserInfo(AbstractUser):
phone = models.BigIntegerField(verbose_name='手机号', null=True)
# 头像
"""
upload_to:指定图片上传的路径
default='avatar/default.png' 默认图片
avatar:存的是文件的路径 avatar/123.png
"""
avatar = models.FileField(upload_to='avatar/', default='static/img/default.jpg', verbose_name='用户头像')
"""
给avatar字段传文件对象 该文件会自动存储到avatar文件下 然后avatar字段只保存文件路径avatar/default.png
"""
# auto_now_add:自定添加当前时间,如果不人为的去修改,这个时间就不会变
create_time = models.DateTimeField(auto_now_add=True)
blog = models.OneToOneField(to='Blog', null=True)
# 站点表
class Blog(models.Model):
site_name = models.CharField(verbose_name='站点名称', max_length=32)
site_title = models.CharField(verbose_name='站点标题', max_length=32)
# 简单模拟 带你认识样式内部原理的操作
site_theme = models.CharField(verbose_name='站点样式', max_length=64) # 存css/js的文件路径 css/my.css
class Category(models.Model):
name = models.CharField(verbose_name='文章分类', max_length=64)
blog = models.ForeignKey(to='Blog', null=True)
class Tag(models.Model):
name = models.CharField(verbose_name='文章标签', max_length=32)
blog = models.ForeignKey(to='Blog', null=True)
class Article(models.Model):
title = models.CharField(verbose_name='文章标题', max_length=128)
desc = models.CharField(verbose_name='文章简介', max_length=255)
# 文章内容有很多 一般情况下都是使用TextField
content = models.TextField(verbose_name='文章内容') # content text
create_time = models.DateField(auto_now_add=True)
# 数据库字段设计优化
up_num = models.BigIntegerField(verbose_name='点赞数', default=0)
down_num = models.BigIntegerField(verbose_name='点踩数', default=0)
comment_num = models.BigIntegerField(verbose_name='评论数', default=0)
# 外键字段
blog = models.ForeignKey(to='Blog', null=True)
category = models.ForeignKey(to='Category', null=True)
tags = models.ManyToManyField(to='Tag',
through='Article2Tag',
through_fields=('article', 'tag')
)
class Article2Tag(models.Model):
article = models.ForeignKey(to='Article')
tag = models.ForeignKey(to='Tag')
class UpAndDown(models.Model):
user = models.ForeignKey(to='UserInfo')
article = models.ForeignKey(to='Article')
is_up = models.BooleanField() # 传布尔值 存0/1
class Comment(models.Model):
user = models.ForeignKey(to='UserInfo')
article = models.ForeignKey(to='Article')
content = models.CharField(verbose_name='评论内容', max_length=255)
comment_time = models.DateTimeField(verbose_name='评论时间', auto_now_add=True)
# 自关联
parent = models.ForeignKey(to='self', null=True) # 有些评论就是根评论