首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Django 2.0 项目实战:扩展Django自带User模型,实现用户注册与登录

用户的注册与登陆是一个网站应该具有的基本功能。网上很多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来美化本项目中的表单。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180506G0A2UU00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券