提交表單及發(fā)表文章
提交表單
1. html表單
<form method="POST" action=""> {% csrf_token %}
<input type="text" name="title" />
<textarea name="content"></textarea>
<button type="submit">發(fā)表</button>
</form>
- input 標(biāo)簽 自開自閉
- textarea 標(biāo)簽 多行文本框 有開閉標(biāo)簽
- submit 按鈕 html表單 一定要有一個submit按鈕
- {% csrf_token %} 一定要寫在form后面
2. 后臺處理
if request.method == "GET":
return render_to_response("xxx.html",
{},
context_instance=RequestContext(request))
else:
title = request.POST["title"].strip()
content = request.POST["content"].strip()
# do anything
csrf 跨站請求偽造
- A為可信站點,B為危險站點。
- 在A登錄后,沒有退出,然后訪問B網(wǎng)站。
- B網(wǎng)站偽造了一個表單,從用戶的瀏覽器提交到A網(wǎng)站。提交到A網(wǎng)站的請求,瀏覽器會自動帶上認證信息,結(jié)果A網(wǎng)站認證通過。
- 如果這個請求是修改密碼,用戶的賬號就被盜了。
Django 防止CSRF
- 給form表單添加一個隱藏字段,一個每個瀏覽器都不一樣的隨機碼。
- 后端驗證隨機碼是否存在。
- 危險網(wǎng)站無法提前探知隨機碼,也就無法偽造請求了。
- {% csrf_token %}
什么是context(環(huán)境)
context_instance = RequestContext(request)
- 沒有來之前就已經(jīng)存在的東西就是環(huán)境
- 模板中不用定義就可以使用的變量就是環(huán)境
- render_to_response 的第二個參數(shù),那個字典,就是環(huán)境。
- RequestContext(request) 是由請求對象提供的環(huán)境,提供了一些模板可以使用的變量,這些變量是從請求中解析出來的。csrf_token 就在其中。
- from django.template import RequestContext
位置參數(shù)與關(guān)鍵字參數(shù)
- do_something(1) 位置參數(shù)
- do_something(in=1, out=2) 關(guān)鍵字參數(shù)
- do_something(1, out=2) 位置參數(shù)在前,關(guān)鍵字參數(shù)在后
- def do_anything(*args, **kwargs): pass
- args 是位置參數(shù)集合,是列表,*解列表為位置參數(shù)
- kwargs 是關(guān)鍵字參數(shù)集合,是字典, ** 是解字典為關(guān)鍵字參數(shù)
uls 與 reverse
{% url 'URL名稱' 位置參數(shù) 關(guān)鍵字參數(shù)=值 %}
reverse('URL名稱', args=[位置參數(shù)], kwargs={關(guān)鍵字參數(shù)})
- 作用相同
- url用于模板中,html中。
- reverse 用于控制器中,python中。
- 他們得到的返回值都是一樣的,都是字符串,就是解析出來的url。
消息組件
from django.contrib import messages
添加消息( 消息級別:DEBUG, INFO, SUCCESS, WARNING, ERROR)
message.add_message(request, messages.ERROR, u'標(biāo)題和內(nèi)容不能為空')
...
context_instance=RequestContext(request)
消息展示
{% if messages %}
{% for message in messages %}
<div class="alert alert-info"> {{ message }} </div>
{% endfor %}
{% endif %}
- 消息只展示一次。
- 給request變量增加了消息屬性。
- message增加在這個請求上面,然后這個請求包裝成一個請求環(huán)境,傳給了模板,所以模板上就有了這個消息。
- message實際上是存在數(shù)據(jù)庫中。在任何地方添加消息之后,如果你一直不輸出,一直不在模板上展示這個消息,讓這個消息一直存著,就算是這個請求返回之后,這個消息也不丟失,直到有一次,頁面里面?zhèn)魅肓苏埱蟮沫h(huán)境,然后再頁面里面展示了消息,這些消息就會被展示出來(包括以前沒有展示的)。
帖子詳情頁面
- 數(shù)據(jù)模型:已定義
- URL:/article/detail/<article_id>
- 控制器:展示一個頁面
- 模板:繼承與base.html,用bootstrap美化,展示必要信息
作業(yè)
- 文章列表頁面,增加“發(fā)表文章”的按鈕
- 增加發(fā)表文章的頁面及功能
- 發(fā)表成功/失敗有消息提示
- 文章列表頁面,文章的標(biāo)題為鏈接,可點擊,點擊跳轉(zhuǎn)到文章詳情
- 完成文章詳情
/article/views.py 注意的代碼
from django.core.urlresolvers import reverse
from django.contrib import messages
from django.contrib.auth.models import User
from django.shortcuts import render_to_response, redirect
from django.template import RequestContext
def create_article(request, block_id):
block_id = int(block_id)
block = Block.objects.get(id=block_id)
if request.method == "GET":
return render_to_response("article_create.html", {"b": block},
context_instance=RequestContext(request))
else: # request.method == "POST"
title = request.POST["title"].strip()
content = request.POST["content"].strip()
if not title or not content:
messages.add_message(request, messages.ERROR, u"標(biāo)題和內(nèi)容均不能為空")
return render_to_response("article_create.html",
{"b": block, "title": title, "content": content},
context_constance=RequestContext(request))
owner = User.objects.all()[0] # TODO:
new_article = Article(block=block, owner=owner, title=title, content=content)
new_article.save()
messages.add_message(request, messages.INFO, u'成功發(fā)布文章')
return redirect(reverse("article_list", args=[block.id]))
注意:python str.format()格式化中文
import sys
reload(sys) # 如果沒法直接調(diào)用setdefaultencoding()方法就加上這句
sys.setdefaultencoding('utf-8')