天天看點

Django1.9開發部落格09- 使用者認證

你應該注意到了一點,當你去建立、修改和删除文章的時候并不需要登入,這樣的話任何浏覽網站的使用者都能随時修改和删除我的文章。這個可不是我想要的!

編輯和删除的認證

我們需要保護post_new, post_edit和post_publish這三個視圖,隻有登入使用者才有權去執行。 django為我們提供了很好的幫助類,其實就是利用了python中的decorators技術。 django中認證的裝飾器位于子產品django.contrib.auth.decorators中,名稱叫login_required。

編輯blog/views.py檔案,在import部分添加如下的導入語句:

1
      
from django.contrib.auth.decorators import login_required
      

然後在post_new, post_edit和post_publish這三個函數上添加@login_required, 類似下面

1
2
3
      
@login_required
def post_new(request):
    [...]
      

好的,現在你再去通路下http://localhost:8000/post/new/,看看有啥變化。

注:如果你仍然能正常進入建立頁面,那可能是你之前在admin界面登陸過。 那麼你需要先退出,通路http://localhost:8000/admin/logout/可以退出,然後你再看下效果。

我剛剛添加的@login_required裝飾器檢測到你尚未登陸的時候會重定向到login頁面, 但是我現在還沒有定義login的模闆頁面,是以這時候會是404錯誤頁面。

使用者登入

django在使用者認證方面做得很好了,我們隻需要去使用它就行。

在mysite/urls.py檔案中,添加下面一行

1
      
url(r'^accounts/login/$', 'django.contrib.auth.views.login')
      

現在這個檔案内容如下:

1
2
3
4
5
6
7
8
9
10
      
from django.conf.urls import patterns, include, url

from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    url(r'^admin/', include(admin.site.urls)),
    url(r'^accounts/login/$', 'django.contrib.auth.views.login'),
    url(r'', include('blog.urls')),
)
      

然後我們再定義一個登陸頁面,建立目錄mysite/templates/registration, 并在裡面建立模闆檔案login.html,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
      
{% extends "mysite/base.html" %}

{% block content %}

    {% if form.errors %}
    <p>Your username and password didn't match. Please try again.</p>
    {% endif %}

    <form method="post" action="{% url 'django.contrib.auth.views.login' %}">
    {% csrf_token %}
    <table>
    <tr>
        <td>` form`.`username`.`label_tag `</td>
        <td>` form`.`username `</td>
    </tr>
    <tr>
        <td>` form`.`password`.`label_tag `</td>
        <td>` form`.`password `</td>
    </tr>
    </table>

    <input type="submit" value="login" />
    <input type="hidden" name="next" value="` next `" />
    </form>
{% endblock %}
      

你可以看到我們仍然使用到了模闆繼承。這個時候可以定義一個mysite/templates/mysite/base.html, 把blog/templates/blog/base.html的内容複制給它即可。

不過我們需要在mysite/settings.py中再添加一個urls配置:

1
      
LOGIN_REDIRECT_URL = '/'
      

這樣的話當使用者直接通路login頁面後登入成功會重定向到文章清單頁面去。

改進顯示

現在的确隻有登入使用者才能修改和删除文章,但是未登入使用者卻能看到這些按鈕, 這個是很不好的體驗。現在如果是未登入使用者的話就把這些按鈕給隐藏掉。

是以我們修改mysite/templates/mysite/base.html如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
      
<body>
    <div class="page-header">
        {% if user.is_authenticated %}
        <a href="{% url 'post_new' %}" class="top-menu"><span class="glyphicon glyphicon-plus"></span></a>
        <a href="{% url 'post_draft_list' %}" class="top-menu"><span class="glyphicon glyphicon-edit"></span></a>
        {% else %}
        <a href="{% url 'django.contrib.auth.views.login' %}" class="top-menu"><span class="glyphicon glyphicon-lock"></span></a>
        {% endif %}
        <h1><a href="{% url 'blog.views.post_list' %}">Django Girls</a></h1>
    </div>
    <div class="content">
        <div class="row">
            <div class="col-md-8">
            {% block content %}
            {% endblock %}
            </div>
        </div>
    </div>
</body>
      

然後修改blog/templates/blog/post_detail.html如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
      
{% extends 'blog/base.html' %}

{% block content %}
    <div class="date">
        {% if post.published_date %}
            ` post`.`published_date `
        {% else %}
            {% if user.is_authenticated %}
                <a class="btn btn-default" href="{% url 'blog.views.post_publish' pk=post.pk %}">Publish</a>
            {% endif %}
        {% endif %}
        {% if user.is_authenticated %}
            <a class="btn btn-default" href="{% url 'post_edit' pk=post.pk %}"><span class="glyphicon glyphicon-pencil"></span></a>
            <a class="btn btn-default" href="{% url 'post_remove' pk=post.pk %}"><span class="glyphicon glyphicon-remove"></span></a>
        {% endif %}
    </div>
    <h1>` post`.`title `</h1>
    <p>{{ post.text|linebreaks }}</p>
{% endblock %}
      

使用者登出

當使用者登入後顯示歡迎語句,Hello ,然後後面跟一個logout連結。還是依靠django幫我們處理logout動作。

修改mysite/templates/mysite/base.html檔案如下:

1
2
3
4
5
6
7
8
9
10
      
<div class="page-header">
    {% if user.is_authenticated %}
    <a href="{% url 'post_new' %}" class="top-menu"><span class="glyphicon glyphicon-plus"></span></a>
    <a href="{% url 'post_draft_list' %}" class="top-menu"><span class="glyphicon glyphicon-edit"></span></a>
    <p class="top-menu">Hello ` user`.`username `<small>&nbsp;<a href="{% url 'django.contrib.auth.views.logout' %}">Log out</a></p>
    {% else %}
    <a href="{% url 'django.contrib.auth.views.login' %}" class="top-menu"><span class="glyphicon glyphicon-lock"></span></a>
    {% endif %}
    <h1><a href="{% url 'blog.views.post_list' %}">Django Girls</a></h1>
</div>
      

很顯然這時候logout肯定會報錯。我們還得做些事情。

對于這方面的詳細文檔請參考:https://docs.djangoproject.com/en/1.9/topics/auth/default/

打開mysite/urls.py檔案,添加一個logout配置:

1
2
3
4
5
6
7
8
9
10
11
      
from django.conf.urls import patterns, include, url

from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    url(r'^admin/', include(admin.site.urls)),
    url(r'^accounts/login/$', 'django.contrib.auth.views.login'),
    url(r'^accounts/logout/$', 'django.contrib.auth.views.logout', {'next_page': '/'}),
    url(r'', include('blog.urls')),
)
      

如果通路網站時出現模闆找不到錯誤,那麼你就在mysite/settings.py中添加如下配置:

1
2
3
4
5
      
# TEMPLATE_DIRS
TEMPLATE_DIRS = (
    os.path.join(BASE_DIR, 'mysite/templates'),
    os.path.join(BASE_DIR, 'blog/templates'),
)
      

好的,現在你已經可以達成如下的效果了:

  1. 需要一個使用者名和密碼登入系統
  2. 在添加/編輯/删除/釋出文章的時候需要登入