1. 程式人生 > >Django專案——讓使用者擁有自己的資料

Django專案——讓使用者擁有自己的資料

一 使用 @login_required  限制訪問

1 限制對 topics 頁面的訪問

learning_logs/views.py程式碼修改如下:

'''
login_required() 的程式碼檢查使用者是否已登入,僅當用戶已登入時, Django 才執行 topics() 的程式碼。
如果使用者未登入,就重定向到登入頁面。
'''
@login_required
def topics(request):
    '''
    使用者登入後, request 物件將有一個 user 屬性,這個屬性儲存了有關該使用者的資訊。
    程式碼 Topic.objects.filter(owner=request.user) 讓 Django 只從資料庫中獲
    取 owner 屬性為當前使用者的 Topic 物件。
    '''
    topics = Topic.objects.filter(owner=request.user).order_by('date_added')
    context = {'topics': topics}
    return render(request, 'learning_logs/topics.html', context)

2 settings.py中增加如下內容:

# 讓 Django 知道到哪裡去查詢登入頁面。
# 如果未登入的使用者請求裝飾器 @login_required 的保護頁面,
# Django 將重定向到 settings.py 中的 LOGIN_URL 指定的 URL
LOGIN_URL = '/users/login/'

二 將資料關聯到使用者

1 修改模型Topic

# -*- coding: utf-8 -*-
from django.db import models
# 匯入了 django.contrib.auth 中的模型 User
from django.contrib.auth.models import User

class Topic(models.Model):
    """ 使用者要學習的主題 """
    text = models.CharField(max_length=200)
    date_added = models.DateTimeField(auto_now_add=True)
    # 在 Topic 中添加了欄位 owner ,它建立到模型 User 的外來鍵關係。
    owner = models.ForeignKey(User)

    def __unicode__(self):
        """ 返回模型的字串表示 """
        return self.text

三 只允許使用者訪問自己的主題

在 views.py 中,對函式 topics() 做如下修改:
'''
login_required() 的程式碼檢查使用者是否已登入,僅當用戶已登入時, Django 才執行 topics() 的程式碼。
如果使用者未登入,就重定向到登入頁面。
'''
@login_required
def topics(request):
    '''
    使用者登入後, request 物件將有一個 user 屬性,這個屬性儲存了有關該使用者的資訊。
    程式碼 Topic.objects.filter(owner=request.user) 讓 Django 只從資料庫中獲
    取 owner 屬性為當前使用者的 Topic 物件。
    '''
    topics = Topic.objects.filter(owner=request.user).order_by('date_added')
    context = {'topics': topics}
    return render(request, 'learning_logs/topics.html', context)

四 保護使用者的主題

1 修改views.py

@login_required
def topic(request, topic_id):
    #  顯示單個主題及其所有的條目
    topic = Topic.objects.get(id=topic_id)
    #  確認請求的主題屬於當前使用者.收到主題請求後,在渲染網頁前檢查該主題是否屬於當前登入的使用者。
    # 如果請求的主題不歸當前使用者所有,我們就引發 Http404 異常,讓 Django 返回一個 404 錯誤頁面。
    if topic.owner != request.user:
        raise Http404
        
    entries = topic.entry_set.order_by('-date_added')
    context = {'topic': topic, 'entries': entries}
    return render(request, 'learning_logs/topic.html', context)

五 保護頁面 edit_entry

'''
頁面 edit_entry 收到 GET 請求時, edit_entry() 將返回一個表單,讓使用者能夠對條目進行編輯。
頁面收到 POST 請求(條目文字經過修訂)時,它將修改後的文字儲存到資料庫中
'''
@login_required
def edit_entry(request, entry_id):
    """ 我們獲取使用者要修改的條目物件,以及與該條目相關聯的主題。在請求方法為 GET 時將執行的 if 程式碼塊中,我們使用實
        參 instance=entry 建立一個 EntryForm 例項。
        這個實參讓 Django 建立一個表單,並使用既有條目物件中的資訊填充它。使用者將看到既有的資料,並能夠編輯它們。
        處理 POST 請求時,我們傳遞實參 instance=entry 和 data=request.POST ,讓 Django 根據既有條目物件建立一個表單例項,
        並根據 request.POST 中的相關資料對其進行修改。然後,我們檢查表單是否有效,如果有效,就呼叫 save() ,且不指定任何實參。
        接下來,我們重定向到顯示條目所屬主題的頁面,使用者將在其中看到其編輯的條目的新版本。"""
    entry = Entry.objects.get(id=entry_id)
    topic = entry.topic
    # 然後檢查主題的所有者是否是當前登入的使用者,如果不是,就引發 Http404 異常。
    if topic.owner != request.user:
        raise Http404
    
    if request.method != 'POST':
        # 初次請求,使用當前條目填充表單
        form = EntryForm(instance=entry)
    else:
        # POST 提交的資料,對資料進行處理
        form = EntryForm(instance=entry, data=request.POST)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('learning_logs:topic',
                                        args=[topic.id]))
    
    context = {'entry': entry, 'topic': topic, 'form': form}
    return render(request, 'learning_logs/edit_entry.html', context)

六 將新主題關聯到當前使用者

@login_required
def new_topic(request):
    """ 新增新主題 """
    if request.method != 'POST':
        # 未提交資料:建立一個新表單
        form = TopicForm()
    else:
        # POST 提交的資料 , 對資料進行處理
        # HttpResponseRedirect 類,使用者提交主題後我們將使用這個類將使用者重定向到網頁 topics 。
        # 函式 reverse() 根據指定的 URL 模型確定 URL ,這意味著 Django將在頁面被請求時生成 URL 。
        # 我們還匯入了剛才建立的表單 TopicForm 。
        # 我們使用使用者輸入的資料(它們儲存在 request.POST 中)建立一個 TopicForm 例項
        # 這樣物件 form 將包含使用者提交的資訊。
        form = TopicForm(request.POST)
        # 函式 is_valid() 核實使用者填寫了所有必不可少的欄位(表單欄位預設都是必不可少的),
        # 且輸入的資料與要求的欄位型別一致(例如,欄位 text 少於 200 個字元)。
        # 這種自動驗證避免了我們去做大量的工作。
        if form.is_valid():
            # 首先呼叫 form.save() ,並傳遞實參 commit=False ,
            # 這是因為我們先修改新主題,再將其儲存到資料庫中
            new_topic = form.save(commit=False)
            new_topic.owner = request.user
            # 將表單中的資料寫入資料庫
            new_topic.save()
            # 使用 reverse() 獲取頁面 topics 的 URL ,並將其傳遞給 HttpResponseRedirect()
            # 後者將使用者的瀏覽器重定向到頁面 topics 。
            # 在頁面 topics 中,使用者將在主題列表中看到他剛輸入的主題。
            return HttpResponseRedirect(reverse('learning_logs:topics'))

    context = {'form': form}
    return render(request, 'learning_logs/new_topic.html', context)

七 測試

使用者1的主題

使用者2的主題