# auth是django自带的用户认证模块:
开发网站的时候可避免的需要设计实现网站的用户系统。此时我们需要实现包括用户注册、用户登录、用户认证、注销、修改密码等功能。
Django内置了强大的用户认证系统--auth,它默认使用 auth_user 表来存储用户数据。
from django.contrib import auth
authenticate()方法提供了用户认证功能,即验证用户名及密码是否正确,一般需要username、password两个关键字参数(参数名不能随意填,要与数据库中auth表字段名一样)
- 如果验证成功会返回一个user对象
- authenticate()会在该 User 对象上设置一个属性来标识后端已经认证了该用户,且该信息在后续的登录过程中是需要的。
# 用法:
from django.contrib import auth
from django.contrib.auth import authenticate, login
def login(request):
username = request.POST['username']
password = request.POST['password']
user = auth.authenticate(request, username=username, password=password)
if user:
return redirect('/index/')
else:
return HttpResponse('username or password error')
- 此函数接受的是一个HTTPRequest对象,以及一个经过认证的User对象
- 此函数实现一个用户登录的功能,本质上会在后端为该用户生成相关session数据
- 调用了login后,以后所有的视图函数都可以使用request.user,它就是当前登录用户
用法示例:
from django.contrib import auth
from django.contrib.auth import authenticate, login
def login(request):
username = request.POST['username']
password = request.POST['password']
user = auth.authenticate(request, username=username, password=password)
if user:
auth.login(request, user)
return redirect('/index/')
else:
return HttpResponse('username or password error')
- 还函数接受一个HttpRequest对象,没有返回值
- 调用该函数时,当前请求的session信息会被全部清除,该用户即使没有登录,使用该函数也不会报错
用法示例:
from django.contrib.auth import logout
from django.contrib import auth
def logout_view(request):
auth.logout(request)
return redirect('/login_view/')
# 用来判断当前请求是否通过了认证,返回布尔值
# 多用于前端判断,在后端做判断时,可以被 if user 替代
# 示例:
def myview(request):
if not request.user.is_authenticated():
return redirect(f'{settings.LOGIN_URL}?next={request.path}')
# auth给我们提供的一个装饰器工具,用来快捷的给某个视图添加登录校验。
# 如果用户没有登录,则会自动跳到django默认的登录URL'/accounts/login/',并传递当前访问url的绝对路径(登录成功后,会重定向到该路径)
# 如果需要自定义登录的URL,则需要在settings.py文件中通过LOGIN_URL进行修改
# 示例:
LOGIN_URL = '/login/'
# 装饰器用法示例:
from django.contrib.auth.decorators import login_required
@login_required
def my_view(request):
pass
auth提供的一个创建新用户/超级用户 的方法,需要提供必要的参数(username、password)等
# 示例:
from django.contrib.auth.models import user
# 创建普通用户
user1 = User.objects.create_user(username='#用户名1',password='#密码1',email='#邮箱地址1'...)
# 创建超级用户
user2 = User.objects.create_super_user(username='#用户名2',password='#密码2',email='#邮箱2'...)
# auth提供的一个检查密码是否正确的方法,需要提供当前请求用户的密码
# auth数据库中存储的是密文密码,用前端输入的密码和数据库中的密文密码直接和前端输入的密码匹配是不能成功的
# 密码正确返回True,否则返回False
# 用法示例:
flag = user.check_password('#密码')
auth提供的一个修改密码的方法,接受要设置的新密码作为参数
# 注意:设置完一定要调用用户对象的save()方法,同样的,设置好的额密码是通过该函数在数据库上存成密文的
用法示例:
def change_password(request):
if request.method == 'GET':
return render(request, 'change_pwd.html')
else:
old_pwd = request.POST.get('old_pwd')
new_pwd = request.POST.get('new_pwd')
re_new_pwd = request.POST.get('re_new_pwd')
if new_pwd == old_pwd:
if request.user.check_password(old_pwd):
# 密码正确再修改
request.user.set_password(new_pwd)
# 记住一定要保存(****)
request.user.save()
return redirect('/login/')
else:
return HttpResponse('旧密码不正确')
else:
return HttpResponse('两次密码输入不一致')
- User对象属性:username,password
- is_staff : 用户是否拥有网站的管理权限,(即能不能登录到后台管理)
- is_superuser : 是否是超级管理员(权限更高,如果is_staff=1,可以任意增删改查任何数据)
- is_active : 是否允许用户登录,设置成False,可以在不删除用户的前提下禁止用户登录
内置的auth_user表字段是固定的,项目中往往需要给它添加字段,但是直接改是不行的,拓展该表有如下两个方式:
建立一张表,通过一对一和内置的auth_user表相关联:
from django.contrib.auth.models import User
class UserDetail(models.Model):
phone = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
user = models.OneToOneField(to=User)
继承内置的AbstractUser,定义一个Model类
这样就可以根据项目的需求灵活设计用户表,又能使用django强大的认证系统
PS:1. 这种方式一开始就要把类建出来,不能中途再试图新增字段,
2. 数据库中的表名就不是 “auth_user” 了,而是变成了 “app01_user”
代码示例:
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
phone = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
### 在settings.py中注册: app名.表名
AUTH_USER_MODEL = "app01.User"
# 操作步骤:
1、备份-->删库-->重新创建数据库
2、所有的app的数据迁移记录删除migrations记录,(除了__init__.py全部都删除)
3、去源码中删除auth和admin这两个app的migrations下除了__init__.py的记录文件
4、数据迁移,同步到数据库中
5、备份的数据,恢复回去
###1、创建多对多关联关系的三种方式
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=5,decimal_places=5)
class Author(models.Model):
name = models.CharField(max_length=32)
# 自己创建第三张表,分别通过外键关联书和作者
class AuthorToBook(models.Model):
author = models.ForeignKey(to="Author", on_delete=models.CASCADE)
book = models.ForeignKey(to="Book", on_delete=models.CASCADE)
方式一这种建法就没法用 book.authors.add(1,2) 这种关联方法了,因为book表中没有authors字段,只能手动写:
book = models.Book.objects.get(pk=1)
models.AuthorToBook.create(book_id=1,author_id=1)
models.AuthorToBook.create(book_id=1,author_id=2)
book1 = models.Book.objects.filter(name='西游记').first()
res = models.AuthorToBook.objects.filter(book=book1)
print(res)
class Book(models.Model):
name = models.CharField(max_length=32)
# 通过ORM自带的ManyToManyField自动创建第三张表
class Author(models.Model):
name = models.CharField(max_length=32, verbose_name="作者姓名")
books = models.ManyToManyField(to="Book")
class Book(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
authors = models.ManyToManyField(to="Author", through="AuthorToBook", through_fields=("book", "author"))
# through_fields接受一个元组('field1','field2'):
# 其中field1是定义当前表对应的外键的名(book),field2是关联目标模型(author)的外键名。
# 自己创建第三张表,并通过ManyToManyField指定关联
class Author(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
class AuthorToBook(models.Model):
author = models.ForeignKey(to="Author", to_field='nid', on_delete=models.CASCADE)
book = models.ForeignKey(to="Book", to_field='nid', on_delete=models.CASCADE)
当我们需要在第三张关系表中存储额外的字段时,就要使用中介模型的方式了,
但是,用这种方式创建的多对多的关联关系,无法使用set、remove、clear、add方法来管理来管理多对多的关系了,因为第三张表中不一定就只有author和book两个字段
需要通过第三张表的model来管理多对多关系(可以使用book.authors):
book = models.Book.objects.get(pk=1)
print(book.authors.all())