python大法攻略

Django项目(三、用户登录与注册的逻辑)

2020-09-10  本文已影响0人  眼君

Django响应页面请求的方式

页面直接响应

当我们直接使用一个html文件去响应某个请求时, 我们不需要在views.py编写视图函数, 而可以直接在urls.py中编写以下逻辑:

#urls.py
...
from django.views.generic import TemplateView
    urlpatterns = [
    ...
    url('$',TemplateView.as_view(template_name='index.html'),name='index')
]

在接下来编写登录逻辑的过程中, 会逐步介绍其它的响应方式。

视图函数编写登录逻辑
#views.py
from django.shortcuts import render
from django.contrib.auth import authenticate,login
from django.contrib.auth.backends import ModelBackend
from django.db.models import Q
from .models import UserProfile


class CustomBackend(ModelBackend):
    def authenticate(self,username=None,password=None,**kwargs):
        try:
            user = UserProfile.objects.get(Q(username=username)|Q(email=username))
            if user.check_password(password):
                return user
        except Exception as e:
            return None
    def user_login(request):
        if request.method == 'POST':
            user_name = request.POST.get('username',"")
            pass_word =  request.POST.get('password',"")
            user = authenticate(username=user_name,password=pass_word)
            if user is not None:
                login(request,user)
                return render(request,"login.html")
            else:
                return render(request,'login.html',{"msg":"用户名或密码错误!"})
        elif request.method == 'GET':
            return render(request,'login.html',{})
#urls.py
...
from users.views import user_login


urlpatterns = [
    ...
    url('^login/$',user_login,name='login')
]

views.py中用到了dango自带的一个用户验证方法authenticate, 如果验证成功, 该方法将返回一个user对象, 否则返回None。
authenticate方法默认验证是通过username和password进行验证, django允许我们使用自定义验证方式, 如上所示, 我们通过继承类ModelBackend来重写authenticate方法,用Q实现或逻辑,当然最后重写的类我们需要在settings.py中进行配置:

#settings.py
...
AUTHENTICATION_BACKENDS = (
    'users.views.CustomBackend',
)

views.py中还用到了login, 这个方法将通过request记录下用户的地址, 通过session和cookies记录用户的状态。

前端通过{% request.user.is_authenticated %}判断用户是否验证。

基于类的方法编写登录逻辑

基于类编写响应逻辑的方式是Django最建议用户使用的:

#users/views.py
...
from django.views.generic.base import View


class LoginView(View):
    def get(self,request):
        return render(request, "login.html",{})

    def post(self,request):
        login_form = LoginForm(request.POST)
        if login_form.is_valid():
            user_name = request.POST.get('username',"")
            pass_word = request.POST.get('password',"")
            user = authenticate(username=user_name,password=pass_word)
            if user is not None:
                if user.is_active:
                    login(request,user)
                    return HttpResponseRedirect(reverse("index"))
                else:
                    return render(request, 'login.html', {"msg": "账号未激活!"})
            else:
                return render(request,'login.html',{"msg":"用户名或密码错误!"})
        else:
            return render(request,'login.html',{"login_form":login_form})
            
#urls.py
...
from users.views import LoginView


urlpatterns = [
    ...
    url('^login/$',LoginView.as_view(),name='login')
]

form表单的使用

Django网站的用户有时需要向服务端发送数据,例如POST方法,Django中有一个类form专门用于对用户传来的数据进行处理。

一般html文件中的<form>元素可以帮助用户传递表单数据:

#xxx.html
<form action="/form" method="post">
    ...
    {% csrf_token %}
</form>

action="/form"表示这次POST请求将会与urls.py中的根路径下的form的URL进行绑定。

创建表单

由于表单对象与model结构相似,也是用到了类似于关系对象映射的方式。我们为了避免混淆,建议在mysite目录下,也即与models.py同级路径下创建一个文件forms.py用于编写表单:

#apps/users/forms.py

from django import forms

#登录用表单
#required=True表示这个字段必填, 如果用户未填就提交会报错
#form字段名称一定要和前端页面中<input>中的name一致, 才能实现数据校验
class LoginForm(forms.Form):
    username = forms.CharField(required=True) 
    password = forms.CharField(required=True)
modelform方式创建表单

由于表单对象与model结构相似,我们也可以直接使用modelform继承models的字段结构生成表单:

#apps/users/forms.py

from django import forms
from users.models import Userprofile 
...
class xxxForm(forms.ModelForm):
    my_filed = forms.CharField()
    class Meta:
        #对应的model
        model = Userprofile
        #筛选对应的字段
        fields = ['username','nickname']

注意, modelform对象加载数据后也可以使用save(commit=True)方法, 将加载的数据存入models对应数据库。

处理表单的视图函数

打开views.py,在里面编写登录验证视图逻辑。首先我们需要引入Django自带的用于登录验证的两个对象,authenticate与login,同时将刚刚创建的表单引入:

#apps/users/views.py
...
from .forms import LoginForm


class LoginView(View):
    def get(self,request):
        return render(request,'login.html',{})
      
    def post(self,request):
        login_form = LoginForm(request.POST)
        #判断校验结果是否有错
        if login_form.is_valid():
            
            user_name = request.POST.get('username',"")
            pass_word =  request.POST.get('password',"")
            user = authenticate(username=user_name,password=pass_word)
            if user is not None:
                login(request,user)
                return render(request,"login.html")
            else:
                return render(request,"login.html",{"msg":"用户名或密码错误!"})
        else:
            #校验结果存储在login_form中传回给前端
            return render(request,'login.html',{"login_form":login_form})

校验结果通过form对象传回给前端:

#template/login.html.py
<form>
    #异常input效果
    <div class= "form {% if login_form.errors.username %}errorput{% endif %}">
    #显示错误日志
    <div>{% for key,error in login_form.errors.items %}{{ key }}:{{ error }}{% endfor %}</div>


</form>

验证码在注册逻辑中的应用

首先,我们考虑实现django验证码的功能, 我们下载一个第三方插件:

pip3 install django-simple-captcha==0.5.5

在settings.py中配置:

#settings.py
...
INSTALLED_APPS = [
    ...
    "captcha",
]

配置urls.py:

#urls.py
...
urlpatterns = [
    ...
    url(r'^captcha/',include('captcha.urls')),
]

然后运行makemigrations和migrate, 至此便完成了图片验证码的所有配置。接下来我们来应用这个配置, 以注册的表单为例:

#apps/users/forms.py

from django import forms
from captcha.fields import CaptchaField

...
#注册用表单
#required=True表示这个字段必填, 如果用户未填就提交会报错
#form字段名称一定要和前端页面中<input>中的name一致, 才能实现数据校验
class RegisterForm(forms.Form):
    email = forms.EmailField(required=True) 
    password = forms.CharField(required=True)
    captcha = CaptchaField()
邮箱验证码

接下来, 我们以用户注册的邮箱激活验证码为例, 演示邮箱验证码的配置。首先在项目根目录新建文件apps/utils/email_send.py, 用于配置邮箱验证码:

#apps/utils/email_send.py,
from random import Random
from django.core.mail import send_mail
from users.models import EmailVerifyRecord
from blogs.settings import EMAIL_FROM


def random_str(randomlength=8):
    str = ''
    chars = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890'
    length = len(chars) - 1
    random = Random()
    for i in range(randomlength):
        str += chars[random.randint(0,length)]
    return str

def send_register_email(email,send_type="register"):
    email_record = EmailVerifyRecord()
    code = random_str(16)
    email_record.code = code
    email_record.email = email
    email_record.send_type = send_type
    email_record.save()

    email_title = ""
    email_boty = ""

    if send_type == 'register':
        email_title = "眼君数据网注册激活链接"
        email_body = "请点击下面的链接激活你的账号:http://127.0.0.1:8000/active/{0}".format(code)

        send_status = send_mail(email_title,email_body,EMAIL_FROM,[email])
        if send_status:
            pass

注意settings.py中也要配置邮箱的发送者:

#settings.py,
EMAIL_HOST = "smtp.qq.com"
EMAIL_PORT = 465
EMAIL_HOST_USER = ""
EMAIL_HOST_PASSWORD = ""
EMAIL_USE_TLS = False
EMAIL_FROM = EMAIL_HOST_USER

在urls.py中的相应配置:

...
from users.views import LoginView,RegisterView,ActiveUserView

urlpatterns = [
    ...
    url(r'^active/(?P<active_code>.*)/$',ActiveUserView.as_view(),name='user_active'),
]

在views.py中编写注册逻辑:

#apps/users/views.py
from django.shortcuts import render
from django.contrib.auth import authenticate,login,logout
from django.contrib.auth.hashers import make_password
from django.contrib.auth.backends import ModelBackend
from django.db.models import Q
from .models import UserProfile,EmailVerifyRecord
from django.views.generic.base import View
from django.http import HttpResponse, HttpResponseRedirect
from .forms import LoginForm,RegisterForm,ForgetForm,ModifyPwdForm
from django.core.urlresolvers import reverse
from utils.email_send import send_register_email
# Create your views here.
...
class ActiveUserView(View):
    def get(self,request,active_code):
        all_records = EmailVerifyRecord.objects.filter(code=active_code)
        if all_records:
            for record in all_records:
                email = record.email
                user = UserProfile.objects.get(email=email)
                user.is_active = True
                user.save()
        else:
            return render(request, "active_fail.html")
        return render(request, "login.html")

class RegisterView(View):
    def get(self,request):
        register_form = RegisterForm()
        return render(request, "register.html",{'register_form':register_form})

    def post(self,request):
        register_form = RegisterForm(request.POST)
        if register_form.is_valid():
            user_name = request.POST.get('email',"")
            if UserProfile.objects.filter(email=user_name):
                return render(request, 'register.html', {"msg": "用户已存在!"})
            pass_word = request.POST.get('password',"")
            user_profile = UserProfile(username=user_name,email=user_name,password=make_password(pass_word),is_active=False)
            user_profile.save()

            send_register_email(user_name,"register")
            return render(request,"login.html")
        else:
            return render(request,'register.html',{'register_form':register_form})
上一篇 下一篇

猜你喜欢

热点阅读