Django之博客系统:用户登陆

使用django有一个好处就是有各种各样的框架可以拿来直接使用。相比flaskdjango自带的框架确实要多很多。比如这一章就要介绍的用户登录。Django拥有一个内置的认证(authentication)框架用来操作用户认证(authentication),会话(sessions),权限(permissions)以及用户组。这个认证(authentication)系统包含了一些普通用户的操作视图(views),例如:登录,登出,修改密码以及重置密码

这个认证(authentication)框架位于django.contrib.auth,被其他Djangocontrib包调用,我们在之前的blog引用中使用这个认证(authentication)框架并为blog创建了一个超级用户来管理站点。

 

我们在创建应用的时候,认证框架已经包含了,在settings.py中的MIDDLEWARE

MIDDLEWARE = [

    'django.middleware.security.SecurityMiddleware',

    'django.contrib.sessions.middleware.SessionMiddleware',

    'django.middleware.locale.LocaleMiddleware',

    'django.middleware.common.CommonMiddleware',

    'django.middleware.csrf.CsrfViewMiddleware',

    'django.contrib.auth.middleware.AuthenticationMiddleware',

    'django.contrib.messages.middleware.MessageMiddleware',

    'django.middleware.clickjacking.XFrameOptionsMiddleware',

]

AuthenticationMiddleware:使用会话(sessions)将用户和请求(requests)进行关联

SessionMiddleware:通过请求(requests)操作当前会话(sessions

 

这个认证(authentication)系统还包含了以下模型(models):

User:一个包含了基础字段的用户模型(model);这个模型(model)的主要字段有:username, password, email, first_name, last_name, is_active

Group:一个组模型(model)用来分类用户

Permission:执行特定操作的标识

 

下面我们就要来创建一个登录的视图。通过执行以下的操作来登录用户

通过提交的表单获取usernamepassword

将得到的用户名和密码和存储在数据库中的进行认证

检查用户是否存在

登录用户到网站并且开始一个认证和会话

 

首先创建一个登录表单,在form.py中添加如下代码:

class LoginForm(forms.Form):

    username=forms.CharField()

password=forms.CharField(widget=forms.PasswordInput)

 

forms.PasswordInput是在密码输入的HTML界面进行渲染的。接着在views.py中添加登录处理的代码

def user_login(request):

    if request.method == 'POST':

        form=LoginForm(request.POST)

        if form.is_valid():

            cd=form.cleaned_data

            user=authenticate(username=cd['username'],password=cd['password'])

            if user is not None:

                if user.is_active:

                    login(request,user)

                    return HttpResponse(u'登录成功')

                else:

                    return HttpResponse(u'登录失败')

            else:

                return HttpResponse(u'非法登录,请注册用户')

    else:

        form=LoginForm()

return render(request,'blog/login.html',{'form':form})

通过使用form=LoginForm(request.POST)得到提交的实例化表单

2 form.is_valid()检查这个表单是否正确,如果正确,通过form.cleaned_data

取出登录的用户名和密码

如果用户是有效的,通过user=authenticate(username=cd['username'],password=cd['password'])

对获取到的用户名和密码进行认证

如果用户可用,则用login(request,user)方法集合用户到会话中然后返回一条成功的消息

 

接下来就是创建url了。在mysiteurls.py中添加url(r'^account/',include('blog.urls')),

 

urlpatterns = [

    url(r'^admin/', admin.site.urls),

    url(r'^blog/',include('blog.urls',namespace='blog',app_name='blog')),

    url(r'^test/$',views.test),

    url(r'^account/',include('blog.urls')),

]

blog应用下的urls.py中添加url(r'^login/$',views.user_login)

urlpatterns = [

    # post views

    url(r'^$', views.post_list_page, name='post_list'),

    url(r'^(?P<post_id>\d+)/share/$',views.post_share,name='post_share'),

    url(r'^(?P<post_id>\d+)/comment/$',views.post_comment,name='post_comment'),

    url(r'^test/$',views.test),

    url(r'^login/$',views.user_login)

]

 

最后来看我们的登录模板,在templates/blog下新建一个login.html

{% extends "base.html" %}

{% block title %}登录{% endblock %}

{% block content %}

    <h1>用户登录</h1>

    <p>请输入用户名和密码:</p>

    <form action="." method="post">

        {{ form.as_p }}

        {% csrf_token %}

        <p><input type="submit" value="Log-in"></p>

    </form>

{% endblock %}

 

现在视图,url,模板都已经具备了,下面我们就是要创建一个真实的用户了。运行服务器进入admin界面进行用户名注册:用超级用户名进入后在Users点击add

输入用户名和帐号

权限设置

这里注意一点,如果忘记了普通用户的用户名和密码,可以登录超级用户帐号进去修改,但是如果连超级用户的密码也忘记了,可以通过如下的方式来修改:

pycharm中进入Python console

输入如下代码操作用户数据库:

from django.contrib.auth.models import User

user=User.objects.get(username='用户名')

user.set_password('密码‘)

user.save()

 

 

下面我们就来开始登录,在浏览器中输入:http://127.0.0.1:8000/account/login/

得到如下的界面

输入用户名和密码后提示登录成功。

django还提供以下视图(views)来处理认证(authentication):

  • login:操作表单(form)中的登录然后登录一个用户
  • logout:登出一个用户
  • logout_then_login:登出一个用户然后重定向这个用户到登录页面

Django提供以下视图(views)来操作密码修改:

  • password_change:操作一个表单(form)来修改用户密码
  • password_change_done:当用户成功修改他的密码后提供一个成功提示页面

Django还包含了以下视图(views)允许用户重置他们的密码:

  • password_reset:允许用户重置他的密码。它会生成一条带有一个token的一次性使用链接然后发送到用户的邮箱中。
  • password_reset_done:告知用户已经发送了一封可以用来重置密码的邮件到他的邮箱中。
  • password_reset_complete:当用户重置完成他的密码后提供一个成功提示页面。

 

blog应用中的urls.py中添加如下代码:

from django.contrib.auth.views import login

from django.contrib.auth.views import logout

from django.contrib.auth.views import logout_then_login

from django.contrib.auth.views import password_change

from django.contrib.auth.views import password_change_done

from django.contrib.auth.views import password_reset

from django.contrib.auth.views import password_reset_done

from django.contrib.auth.views import password_reset_confirm

from django.contrib.auth.views import password_reset_complete

 

然后在urlpatterns中添加对应的路径处理函数

urlpatterns = [

    # post views

    url(r'^$', views.post_list_page, name='post_list'),

    url(r'^(?P<post_id>\d+)/share/$',views.post_share,name='post_share'),

    url(r'^(?P<post_id>\d+)/comment/$',views.post_comment,name='post_comment'),

    url(r'^test/$',views.test),

    url(r'^login/$',login),

    url(r'^logout/$', logout, name='logout'),

    url(r'^logout-then-login/$', logout_then_login, name='logout_then_login'),

    url(r'^password-change/$', password_change, name='password_change'),

    url(r'^password-change/done/$', password_change_done, name='password_change_done'),

    url(r'^password-reset/$',

            password_reset,

            name='password_reset'),

    url(r'^password-reset/done/$',

        password_reset_done,

        name='password_reset_done'),

    url(r'^password-reset/confirm/(?P<uidb64>[-\w]+)/(?P<token>[-\w]+)/$',

        password_reset_confirm,

        name='password_reset_confirm'),

    url(r'^password-reset/complete/$',

        password_reset_complete,

        name='password_reset_complete'),

]

 

比如输入http://127.0.0.1:8000/account/password-change/则会自动跳转到密码修改的界面:

那么现在我们来优化下我们的登陆功能,前面在登陆完成以后跳转到一个页面提示跳转成功。现在我们来优化下这个功能,登陆后跳转到登陆前的界面

首先在url

我们将url(r'^login/$',views.user_login)替换成url(r'^login/$',login,name="login")

也就是我们使用django中的登陆认证模块,使用这种认证模块必须在templates目录下创建一个新的目录命名为registration。这个路径是Django认证(authentication)视图(view)期望你的认证(authentication)模块(template)默认的存放路径。如果没有这个路径的话会提示如下的错误:

在这个新目录中创建一个新的文件,命名为login.html,然后添加如下代码:

{% extends "blog/base.html" %}

{% block title %}Log-in{% endblock %}

{% block content %}

  <h1>用户登录</h1>

  {% if form.errors %}

    <p>

      用户或密码不匹配,请输入正确的用户名和密码.

    </p>

  {% else %}

    <p>填入下面的信息登陆:</p>

  {% endif %}

  <div class="login-form">

    <form action="{% url 'login' %}" method="post">

      {{ form.as_p }}

      {% csrf_token %}

      <input type="hidden" name="next" value="{{ next }}" />

      <p><input type="submit" value="Log-in"></p>

    </form>

  </div>

 {% endblock %}

我们添加了一个隐藏的HTML<input>元素来提交叫做next的变量值。当你在请求(request)中传递一个next参数(举个例子:http://127.0.0.1:8000/account/login/?next=/account/),这个变量是登录视图(view)首个设置的参数。

 

next参数必须是一个URL。当这个参数被给予的时候,Django登录视图(view)将会在用户登录完成后重定向到给予的URL。也就是在登陆完成后URL将从http://127.0.0.1:8000/account/login/?next=/account/跳转到http://127.0.0.1:8000/account

settings.py中添加如下配置。LOGIN_URLLOGOUT_URL

from django.core.urlresolvers import reverse_lazy

LOGIN_URL = reverse_lazy('login')

LOGOUT_URL = reverse_lazy('logout')

这些设置的意义:

 

LOGIN_URL:重定向用户登录的URL(例如:使用login_required装饰器(decorator))。

LOGOUT_URL:重定向用户登出的URL

 

我们使用reverse_lazy()来通过它们的名字动态构建URLreverse_lazy()方法就像reverse()所做的一样reverses URLs,但是你可以通过使用这种方式在你项目的URL配置被读取之前进行reverse URLs

 

我们现在来测试下,在post_list_page中使用login_required进行修饰

@login_required

def post_list_page(request):

    object_list = Post.objects.all()

    paginator = Paginator(object_list, 1)  # 3 posts in each page

    page = request.GET.get('page')

new_comment = None

 

注意:这里的使用方式比较灵活。我们也可以在login_required中进行登录跳转界面的设置,这里设置了的话那么在settings.py中就不用设置了LOGIN_URL

@login_required(login_url='/account/login')

def post_list_page(request):

    object_list = Post.objects.all()

    paginator = Paginator(object_list, 1)  # 3 posts in each page

    page = request.GET.get('page')

    new_comment = None

 

下面我来进行测试,在浏览器中输入http://127.0.0.1:8000/blog。由于没有登录所以自动会跳转到http://127.0.0.1:8000/account/login/?next=/blog/进行用户登陆。这里并且传递了next的参数

输入用户名和密码后重新回到了http://127.0.0.1:8000/blog的地址并且显示了博客内容

既然已经实现了登陆,那么下面来看下退出登陆。首先在registration中创建一个logged_out.html。注意这个名称必须是logged_out,否则在退出登录的时候会自动跳转到admin/logout也就是管理页面的登出界面。文件代码如下:

{% extends "blog/base.html" %}

{% block title %}Logged out{% endblock %}

{% block content %}

  <h1>用户退出</h1>

  <p>你已经退出登陆<a href="{% url "login" %}">重新登陆</a></p>

{% endblock %}

 

在我们的博客显示界面添加退出登陆的链接:

<span class="user">

       {% if request.user.is_authenticated %}

         你好 {{ request.user.first_name }},

         <a href="{% url "logout" %}">退出</a>

       {% endif %}

</span>

页面显示如下

点击退出跳转到退出登陆的界面。我们点击重新登陆

我们点击重新登陆并再次输入用户名和密码却提示出错:

原因在于,我们在点重新登陆的时候,页面跳转到http://127.0.0.1:8000/account/login/。请注意,这个URL并没有next参数,也就是说只是纯粹的一个登录界面,在login.html中由于无法获取到next参数的值因此无法回到退出前的界面。此时url变为http://127.0.0.1:8000/accounts/profile/。我们在url中并没有这个路由,因此报错

 

那么如何解决呢,方法是在settings.py中设置登陆后的跳转界面

LOGIN_REDIRECT_URL = reverse_lazy('list')

并且在应用的urls.py中添加了路由

url(r'^$',views.post_list_page,name='list'),

这样在重新登陆后,界面将跳转到list这个url。这样我们再重新登录的时候就不会有问题了

 

django的模块中还有修改密码,重置密码等功能,用法都是差不多的。这里简单介绍下

修改密码:

registration/目录下添加一个新的文件命名为password_form.html。添加如下代码:

{% extends "/blog/base.html" %}{% block title %}Change you password{% endblock %}{% block content %}

  <h1>Change you password</h1>

  <p>Use the form below to change your password.</p>

  <form action="." method="post">

    {{ form.as_p }}

    <p><input type="submit" value="Change"></p>

    {% csrf_token %}

  </form>{% endblock %}

在相同的目录下创建另一个文件,命名为password_change_done.html来显示密码修改成功,为它添加如下代码:

{% extends "blog/base.html" %}{% block title %}Password changed{% endblock %}{% block content %}

  <h1>Password changed</h1>

  <p>Your password has been successfully changed.</p>

 {% endblock %}

 

posted @ 2018-03-18 22:06  red_leaf_412  阅读(686)  评论(0编辑  收藏  举报