用户的注册与登陆是一个网站应该具有的基本功能。网上很多Django关于实现用户注册与登录的教程都是用Django 1.X写的,比较老了,所以小编我觉得有必要亲自动手用Django 2.0重写用户注册与登陆教程。另外网上很多教程忽略了Django Auth模块自带的User模型而重新建立了自己用户的模型,小编我一看到这种教程就会投去一脸鄙视的目光。一个网站会什么要有两个User模型? Why? Why? 本文会教你在不自建User模型的情况下实现用户的注册与登陆。另外,我们会对Django Auth自带的User模型进行扩展,允许用户添加更多的个人信息。由于全文非常的长,我们会分3部分推送,欢迎订阅我的微信公众号【Python与Django大咖之路】获取最新文章。
总体开发思路
我们要利用Django 2.0开发一个叫users的app,来实现以下6项功能。我们一共将分3篇文章来介绍。本文只介绍用户的注册和登录部分。
用户注册: 注册完成后转到登录页面
用户登录: 登录完成后转到用户资料页面
用户资料页面: 查看用户注册信息,并提供编辑资料按钮
用户资料编辑:编辑完成后转到用户资料查看页面
用户密码重置
用户退出登陆
由于Django Auth自带的User模型字段有限,我们还需要自定义模型UserProfile对其扩展。
第一步: 创建名叫users的app并修改设置setting.py
我们假设你已经利用Django创建了一个叫mysite的项目,你可以在终端cmd窗口cd进入这个目录,并输入以下命令创建一个叫users的app。
然后找到mysite/settings.py里将'users' 加到INSTALLED_APPS里,如下图所示。
INSTALLED_APPS = [
'reg.apps.RegConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'users',
]
第二步: 建立名叫UserProfile的模型(Model)
我们并没有改变Django Auth自带的User模型,也没有建立新的User模型。UserProfile只是对User模型的扩展, 与User是1对1的关系。找到users/models.py, 并创建如下UserProfile模型。由于我们引用了Django Auth自带的User模型,所以我们必需开始先把它import进来。
fromdjango.dbimportmodels
fromdjango.contrib.auth.modelsimportUser
classUserProfile(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE,related_name='profile')
org = models.CharField(
'Organization',max_length=128,blank=True)
telephone = models.CharField(
'Telephone',max_length=50,blank=True)
mod_date = models.DateTimeField('Last modified',auto_now=True)
classMeta:
verbose_name ='User Profile'
def__str__(self):
returnself.user
然后你可以在终端输入以下命令,就可以创建UserProfile的数据表。
第三步:配置URL
小编我是自上而下思考的,所以我习惯上先编写URL,再写视图view。从URL配置上你应该可以直接理解我们想实现的6个功能。下面是users/urls.py里的全部代码。你应该注意到,我们给动态链接/register/取了个名字’register', 这样我们就可以在html模板里可以通过{% url 'users:register' %}调用这个链接了。
fromdjango.urlsimportre_path
from.importviews
app_name ='users'
urlpatterns = [
re_path(r'^register/$',views.register,name='register'),
re_path(r'^login/$',views.login,name='login'),
re_path(r'^user/(?P
\d+)/profile/$',views.profile,name='profile'),
re_path(r'^user/(?P
\d+)/profile/update/$',views.profile_update,name='profile_update'),
re_path(r'^user/(?P
\d+)/pwdchange/$',views.pwd_change,name='pwd_change'),
re_path(r'^logout/$',views.logout,name='logout'),
]
另外找到mysite/urls.py, 把我们这个app的URLs也加进去,如下图所示。这样当用户访问/accounts/register/时,浏览器会调用views.py里的register函数。
urlpatterns = [
url(r'^admin/',admin.site.urls),
url(r'^accounts/',include('users.urls')),
]
第四步: 编写试图(view)
我们需要编写register和login两个视图, 让用户通过表单向我们提交数据,并处理这些数据。因为这两个视图都需要用表单,所以我们先在users目录下新建forms.py,然后创建两个form,一个RegistrationForm,一个LoginForm。代码如下:
fromdjangoimportforms
fromdjango.contrib.auth.modelsimportUser
importre
defemail_check(email):
pattern = re.compile(r"\"?([-a-zA-Z0-9.`?{}]+@\w+\.\w+)\"?")
returnre.match(pattern,email)
classRegistrationForm(forms.Form):
username = forms.CharField(label='Username',max_length=50)
email = forms.EmailField(label='Email',)
password1 = forms.CharField(label='Password',widget=forms.PasswordInput)
password2 = forms.CharField(label='Password Confirmation',widget=forms.PasswordInput)
# Use clean methods to define custom validation rules
defclean_username(self):
username =self.cleaned_data.get('username')
iflen(username)
raiseforms.ValidationError("Your username must be at least 6 characters long.")
eliflen(username) >50:
raiseforms.ValidationError("Your username is too long.")
else:
filter_result = User.objects.filter(username__exact=username)
iflen(filter_result) >:
raiseforms.ValidationError("Your username already exists.")
returnusername
defclean_email(self):
email =self.cleaned_data.get('email')
ifemail_check(email):
filter_result = User.objects.filter(email__exact=email)
iflen(filter_result) >:
raiseforms.ValidationError("Your email already exists.")
else:
raiseforms.ValidationError("Please enter a valid email.")
returnemail
defclean_password1(self):
password1 =self.cleaned_data.get('password1')
iflen(password1)
raiseforms.ValidationError("Your password is too short.")
eliflen(password1) >20:
raiseforms.ValidationError("Your password is too long.")
returnpassword1
defclean_password2(self):
password1 =self.cleaned_data.get('password1')
password2 =self.cleaned_data.get('password2')
ifpassword1andpassword2andpassword1 != password2:
raiseforms.ValidationError("Password mismatch. Please enter again.")
returnpassword2
classLoginForm(forms.Form):
username = forms.CharField(label='Username',max_length=50)
password = forms.CharField(label='Password',widget=forms.PasswordInput)
# Use clean methods to define custom validation rules
defclean_username(self):
username =self.cleaned_data.get('username')
ifemail_check(username):
filter_result = User.objects.filter(email__exact=username)
if notfilter_result:
raiseforms.ValidationError("This email does not exist.")
else:
filter_result = User.objects.filter(username__exact=username)
if notfilter_result:
raiseforms.ValidationError("This username does not exist. Please register first.")
returnusername
千万不要上面的代码吓到。之所以代码这么长是因为我们用clean方法加入了很多表单验证项,比如检查用户名是否过短,用户名是否已经存在。如果你把表单验证拿掉,其实代码非常少。我之所以加上这些验证规则,是让你了解最真实的网站开发。
当然你也可以不用新建forms.py而直接在html模板里写表单,但我并不建议这么做。用forms.py的好处显而易见:
所有的表单在一个文件里,非常便于后期维护,比如增添或修订字段。
forms.py可通过clean方法自定义表单验证,非常便捷。不用在views.py里再进行表单验证(比如检查用户是否已存在),逻辑上更清晰。
我们的视图users/views.py是这样子的。
fromdjango.shortcutsimportrender,get_object_or_404
fromdjango.contrib.auth.modelsimportUser
from.modelsimportUserProfile
fromdjango.contribimportauth
from.formsimportRegistrationForm,LoginForm,ProfileForm,PwdChangeForm
fromdjango.httpimportHttpResponseRedirect
fromdjango.urlsimportreverse
fromdjango.contrib.auth.decoratorsimportlogin_required
defregister(request):
ifrequest.method =='POST':
form = RegistrationForm(request.POST)
ifform.is_valid():
username = form.cleaned_data['username']
email = form.cleaned_data['email']
password = form.cleaned_data['password2']
# 使用内置User自带create_user方法创建用户,不需要使用save()
user = User.objects.create_user(username=username,password=password,email=email)
# 如果直接使用objects.create()方法后不需要使用save()
user_profile = UserProfile(user=user)
user_profile.save()
returnHttpResponseRedirect("/accounts/login/")
else:
form = RegistrationForm()
returnrender(request,'users/registration.html',{'form': form})
deflogin(request):
ifrequest.method =='POST':
form = LoginForm(request.POST)
ifform.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = auth.authenticate(username=username,password=password)
ifuseris not None anduser.is_active:
auth.login(request,user)
returnHttpResponseRedirect(reverse('users:profile',args=[user.id]))
else:
# 登陆失败
returnrender(request,'users/login.html',{'form': form,
'message':'Wrong password. Please try again.'})
else:
form = LoginForm()
returnrender(request,'users/login.html',{'form': form})
我们先看下views.register函数是怎么工作的:
当用户通过POST方法提交表单,我们先验证表单RegistrationForm的数据是否有效。如果有效,我们先用Django User模型自带的create_user方法创建user对象,再创建user_profile。用户通过一张表单提交数据,我们实际上分别存储在两张表里。
如果用户注册成功,我们通过HttpResponseRedirect方法转到登陆页面
如果用户没有提交表单或不是通过POST方法提交表单,我们转到注册页面,生成一张空的RegistrationForm
我们再看下views.login函数是怎么工作的:
当用户通过POST方法提交表单,我们先验证表单LoginForm的数据是否有效。如果有效,我们调用Django自带的auth.authenticate()来验证用户名和密码是否正确。如果正确且用户是活跃的,我们调用auth.login()来进行登录。
如果用户登录失败,会重新转到登录页面,并返回错误信息。
如果用户登录成功,我们通过HttpResponseRedirect方法转到用户个人信息页面
如果用户没有提交表单或不是通过POST方法提交表单,我们转到登录页面,生成一张空的LoginForm
第五步: 编写HTML模板(Template)
在users目录下创建/templates/users/文件夹,编写html模板registration.html和login.html。其目录结构应该如下图所示:
下面是模板registration.html的代码:
{% block content %}
{% csrf_token %}
{% for field in form %}
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{% if field.help_text %}
{{ field.help_text|safe }}
{% endif %}
{% endfor %}
{% endblock %}
下面是模板login.html的代码:
{% block content %}
Login
{% if message %}
{{ message }}
{% endif %}
{% csrf_token %}
{% for field in form %}
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{% if field.help_text %}
{{ field.help_text|safe }}
{% endif %}
{% endfor %}
Register
{% endblock %}
第六步:实战效果
现在你可以在终端输入以下命令,看实战效果了。
打开浏览器,访问http://127.0.0.1:8000/accounts/register/和http://127.0.0.1:8000/accounts/login/,你就应该看到如下效果了。
当你注册时两次密码不一致,或用户名太短,或用户名已存在,表单会告诉你错误在哪里,如下图所示:
当你成功登录时,你会被转到个人资料页面。你将被允许修改自己的信息,如下图所示:
结语
本文利用Django 2.0实现了用户注册与登录的两个功能,扩展了Django自带的User模型,并分享了代码。接下来我会分享如何实现查看用户资料,允许用户修改自己资料,修改密码和退出登录的其它4个功能。另外,我会专门介绍如何调用静态文件css和js来美化本项目中的表单。
领取专属 10元无门槛券
私享最新 技术干货