关于Django登录功能实现的几种方案
方案一,采用django自带的login
优缺点:缺少css样式,适合敏捷开发,对于前端样式上需要花一些功夫;好处就是错误提示不需要我们刻意去实现
参考图片:
具体实现:
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样式
参考图片:
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>