关于Django登录功能实现的几种方案

方案一,采用django自带的login

优缺点:缺少css样式,适合敏捷开发,对于前端样式上需要花一些功夫;好处就是错误提示不需要我们刻意去实现

参考图片:

image

image

具体实现:

urls.py:

from django.contrib.auth import views as auth_views
from account.forms import MyAuthenticationForm
urlpatterns = [
    path('login/', auth_views.LoginView.as_view(
        template_name="account/login.html", authentication_form=MyAuthenticationForm),name='login'),       #登录用
    path('logout/', auth_views.LogoutView.as_view(next_page="/"), name='logout'),  #登出用

forms.py:

from django.contrib.auth.forms import AuthenticationForm,

from captcha.fields import CaptchaField,CaptchaTextInput   # 图片验证码,可以不加

# 图片验证码,可以不加
class CustomCaptchaTextInput(CaptchaTextInput): 
    template_name = 'custom_captcha.html'

class MyAuthenticationForm(AuthenticationForm):
    captcha = CaptchaField(label="验证码", required=True,error_messages={'invalid':'验证码错误'},
                           widget=CustomCaptchaTextInput)  # 这个是实现验证码,可以不加
    
    def __init__(self, *args, **kwargs):
        super(MyAuthenticationForm, self).__init__(*args, **kwargs)
        self.fields['username'].widget.attrs['placeholder'] = u'输入账号'
        self.fields['password'].widget.attrs['placeholder'] = u'输入密码'
        self.fields['captcha'].widget.attrs['placeholder'] = u'验证码'   #可以不加

login.html:

<style>
    .form-inline label {
        width: 20%;
        display: block;
        text-align: left;
    }

    .form-inline input {
        width: 80%;
    }

    .errorlist {
        color: red;
    }
    #id_captcha_1 {
        width: 150px;
        margin-right: 10px;
    }
</style>
<form class="form-account" method="post">
    {% csrf_token %}
    <h2 class="form-account-heading text-center">登录平台</h2>
    {{ form.non_field_errors }}
    {% for field in form %}
    <div class="form-group form-inline{% if field.name != 'captcha' %} d-flex justify-content-between{% endif %}">
        {{ field.label_tag }} {{ field }}
        {% if field.help_text %}
        <p class="help">{{ field.help_text|safe }}</p>
        {% endif %}
        <p>{{ field.errors }}</p>
    </div>
    {% endfor %}
    <button class="btn btn-lg btn-primary btn-block" type="submit">登录</button>
</form>

方案二,自定义View,自定义Form

优缺点:虽然自定义程度较高,但是更符合我们的预期,可控的前端样式;不需要根据表单渲染出的id再去写css样式

参考图片:

image

urls.py:

from accounts import views
from django.contrib.auth.views import LogoutView


app_name = 'account'

urlpatterns = [
    path('login/', views.AccountLoginView.as_view(), name='login'),
    path('logout/', LogoutView.as_view(next_page="/"), name='logout'),
]

views.py:

from django.views import View

class AccountLoginView(View):
    def post(self, request):
        f = forms.LoginForm(request.POST)
        if f.is_valid():  # 通过form校验数据格式
            user_obj = authenticate(username=f.cleaned_data["username"], password=f.cleaned_data["password"])  # 认证提交的表单是否满足数据库记录
            if user_obj:
                login(request, user_obj)  # 登录当前用户
                next_url = self.get_redirct_url(user_obj)  # 这里通过鉴定用户角色,返回相应的url
                if next_url:
                    messages.success(request, "欢迎登录")
                    return redirect(next_url)

        messages.success(request, '登录失败,错误的账号密码')
        return redirect('home')
    
    def get_redirct_url(self, user):
        # 判断用户属组,重定向至相应的页面
        client_group = user.groups.filter(name="client")
        doctor_group = user.groups.filter(name="doctor")
        if client_group:
            return reverse("client:home")  #  /client/index/
        elif doctor_group:
            return reverse("doctor:home")
        elif user.is_superuser:
            return reverse("admin:index")

forms.py

from django import forms

class CustomCharField(forms.CharField):
    # 继承CharField并为其添加class使其带有bootstrap样式
    def __init__(self, *, max_value=None, min_value=None, **kwargs):
        super().__init__(**kwargs)


    def widget_attrs(self, widget):
        attrs = super().widget_attrs(widget)
        attrs["class"] = 'form-control form-control-sm bg-light'
        attrs["placeholder"] = self.label
        return attrs


class LoginForm(forms.Form):
    username = CustomCharField(
        label="Username",
        widget=forms.TextInput(
            attrs={"id": "login_username", "autocomplete": "new-username"}))

    password = CustomCharField(
        label="Password",
        strip=False,
        widget=forms.PasswordInput(attrs={'autocomplete': 'current-password',"id": "login_password"}),
    )

home.html

<div class="modal-body">
    <form class="form-account" method="post" action="{% url 'account:login' %}">
        <div class="row row-cols-2 row-cols-md-2">
            {% csrf_token %}
            {{ form.non_field_errors }}
            {% for field in login_form %}
            <div class="form-group col-5">
                {{ field.label_tag }} {{ field }}
                {% if field.help_text %}
                <small class="form-text text-muted text-right">{{ field.help_text|safe }}</small>
                {% endif %}
                {% if field.errors %}
                <p>{{ field.errors }}</p>
                {% endif %}
            </div>
            {% endfor %}
        </div>
        <div class="modal-footer">
            <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
            <button type="submit" class="btn btn-primary">Login</button>
        </div>
    </form>
</div>

方案三,自定义view,form定或不定都行,主要是页面渲染采用第三方包

优缺点:新引入的包不仅省了方案二的自定义FIeld,还带了其他功能,这里只写form渲染。缺点就是为了渲染字段而引入一个包。

参考图片:

...参考方案二

pip:

# 两个包都可以:django-bootstrap、django-crispy-forms
pip install django-bootstrap
# 或
pip install django-crispy-forms

# 参考用法:github.com 搜索

forms.py \ views.py \ urls.py参考方案二

index.html:

{% load bootstrap %}
<div class="modal-body">
    <form class="form-account" method="post" action="{% url 'account:login' %}">
        <div class="row row-cols-2 row-cols-md-2">
            {% csrf_token %}
            {{ form|bootstrap }}
        </div>
        <div class="modal-footer">
            <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
            <button type="submit" class="btn btn-primary">Login</button>
        </div>
    </form>
</div>

{# 或者 #}

{% load crispy %}
<div class="modal-body">
    <form class="form-account" method="post" action="{% url 'account:login' %}">
        <div class="row row-cols-2 row-cols-md-2">
            {% csrf_token %}
            {{ form|crispy }}
        </div>
        <div class="modal-footer">
            <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
            <button type="submit" class="btn btn-primary">Login</button>
        </div>
    </form>
</div>
posted @ 2022-01-05 15:12  lisicn  阅读(823)  评论(0编辑  收藏  举报