国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

跟我一起Django-06模板和表單處理

2019-11-14 17:33:58
字體:
來源:轉載
供稿:網友

http://m.survivalescaperooms.com/ganiks/

6. 模板和表單處理1 模板1.1 理解Contexts1.2 模板語言語法1.2.1 模板過濾器1.2.2 標簽Tag1.2.3 Blocks和Extends跳出當前模板和其他模板交互1.2.4 include2 表單2.1 定義表單2.1.1 基于模型的表單2.1.2 保存ModelForm2.1.3 區別于Model2.1.4 繼承表單2.2 填寫表單2.3 驗證和清理2.4 顯示表單2.4.1 顯示全部表單2.4.2 逐個顯示表單2.4.3 Widget2.4.4 重寫一個變量的默認widget

1 模板

Django的模板系統絕不僅僅是用于生成HTML,還有 log文件、Email正文、CSV文件等任何文本格式文件。

1.1 理解Contexts

Django 把傳遞給一個渲染模板的信息稱之為 context, 實質上就是包含鍵值對的類似字典的 Context對象

準備Contexts有兩種方式:

一種是上一篇中用到的,將Contexts作為參數傳遞

render_to_response("person/detail.html", {"person":person})

直接將數據作為render_to_response的參數傳遞;
或者在使用通用視圖時把extra_context參數加上

   return object_list(request,        queryset = Person.objects.filter(last__istartswith=last_name)    }

第二種方式是通過 context處理器, 這個東東類似中間件,可以定義各種函數,在模板渲染之前來把鍵值對附加到所有context上去。
這也是認證框架這樣的特性,為什么能保證特定的數據在全站范圍里都能訪問到的原因。

def breadcrumb_PRocessor(request):    return {        'breadcrumb': request.path.split('/')    }

通常處理器都放在根目錄的 context_processors.py文件中或是app的目錄中;
另外還需要在 settings.py中激活才可以使用, 通常是在一個叫做TEMPLATE_CONTEXT_PROCESSORS 的元組中, 類似中間件的激活。

1.2 模板語言語法

跟其他一些非xml的 模板語言如Smarty相比, Django的模板語言沒有要保持 XHTML兼容性的意思,
而是用特殊的字符來把(模板變量以及邏輯命令)和靜態內容(HTML)分開來。

跟其他模板語言一樣,Django模板系統也有 單獨命令 和 模塊級命令 , 分別是{{ variable }}, {% command %}

下面的例子渲染context內容:{"title_text":"My WebPage", "object_list": ["One", "Two", "Three"]}

<html>    <head>        <title>{{ title_text }}</title>    </head>    <body>        <ul>        {% for item in object_list %}            <li>{{ item }}</li>        {% endfor %}        </ul>    </body></html>

陷阱:Django在模板中輸出context變量的時候,會隱式調用 unicode方法, 所以對象以及其他非字符串變量會被盡量轉換成 Unicode字符串。
如果你要輸出沒有定義 unicode 方法的對象,在模板里是看不到它們的,因為Python表示對象用的是 < > ,正好在html中啥也不是,故不顯示。

>>> print object()<object object at 0x40448>

1.2.1 模板過濾器

類似 UNIX 管道

  • string|lower
  • person.is_avaliable|yesno:"Yes,No"

1.2.2 標簽Tag

if, ifequal, for, endfor, block, include, extends ...

{% ifequal object_list|length 10 %}
{% if object_list|lengthis 10 %}

模塊級命令如 if for , 可以修改它們的局部 context, 很實用

如 for 提供了 {{ forloop }}局部變量, 用法有 forloop.first .last .counter .counter0

跳出當前模板和其他模板交互
通過模板繼承和模板包含來完成代碼的組合和重用
繼承通過 blocks extends 實現;包含通過 include 實現

1.2.3 Blocks和Extends

  • {% extends %} 必須在模板的頂部調用,并告知渲染引擎這個模板是從一個更高級的模板繼承而來
  • {% blocks %} 是一個模塊級標簽,一個模板中可以定義多個block, 預備讓那些要擴展它的模板去填充的小節

舉個例子,三層網站布局

  • /

    • /section1/
    • /section2/

      • /section1/page1/
      • /section1/page2/
#base.html<html><head><title>{% block title %}My Web Site{% endblock %}</title></head></html><div id="content">{% block content %}{% endblock %}</div>section1.html{% extends "base.html" %}{% block title %} Section1 {% endblock %}page1.html{% extends "section1.html" %}{% block content %} This Page 1 {% endblock %}page2.html{% extends "section1.html" %}{% block content %} This Page 2 {% endblock %}

1.2.4 include

很簡單,類似php的include,實現代碼重用

http://m.survivalescaperooms.com/ganiks/p/django-template-and-forms.html

2 表單

Django提供了 forms 庫來把框架里的三個主要的組件聯系在一起:

  • 模型里定義的數據庫字段
  • 模板里顯示的HTML表單標簽
  • 驗證用戶輸入和顯示錯誤信息的能力

2.1 定義表單

表單處理的核心類Form 其實跟 Model 看上去是基本相同的, 它們都是處理 變量對象集合, 只是代表的意義不同,一個是Web表單,一個是數據表

有了Form類,我們不光可以輕松處理跟Model模型 100%匹配的表單,還可以隱藏或是省略特定變量,或是把多個model里的變量放在一個表單,或是處理和數據庫存儲毫無關系的表單, 非常靈活。

from django import newforms as formsclass PersonForm(forms.Form):    first = forms.CharField(max_length=100, required=True)    last = forms.CharField(max_length=100, required=True)    middle = forms.CharField(max_length=100)

2.1.1 基于模型的表單

Django允許你使用Form變形 ModelForm 類為任何 Model類或實例取得一個Form子類,
一個ModelForm和普通Form基本一樣,但是包含了一個Meta嵌套類(類似Model里的Meta),內含一個必須的屬性 model

下面重新定義下上面的 Form

from django import newforms as formsfrom mysite.myapp.models import Personclass PersonForm(forms.ModelForm):    class Meta:        model = Person

完美體現了Django的DRY don't repeat yourself 的原則

2.1.2 保存ModelForm

基于模型創建的表單跟手動生成的表單有一個很重要的區別是, save方法

from mysite.myapp.forms import PersonFormform = PersonForm({'first':'John', 'last':'Doe'})new_person = form.save()

你經常會需要在數據,從表單提交后,存儲到數據庫之前,修改它們;

而最好還是在后一個時間段修改,因為這時候你修改的是Python值,而不是POST數據。

為了能讓在save之前修改, save方法提供了一個可選的commit參數(默認是True), 控制你是否真的更新數據庫。

from mysite.myapp.forms import PersonFormform = PersonForm({'first':'John', 'last':'Doe'})new_person = form.save(commit=False)new_person.middle = 'Danger'new_person.save()

如果使用 commit=False 來延遲保存的ModelForm包含了相關對象, Django會給表單(不是Model對象的結果)添加一個額外的方法 save_m2m, 讓你正確安排時間的順序。

form = PersonForm(input_including_related_objects)new_person = form.save(commit=False)new_person.middle = 'Danger'new_person.save()form.save_m2m()

如果沒有最后的 save_m2m(), related objects會出問題的。

2.1.3 區別于Model

繼承模型的表單是非常方便,但是有時候我們需要排除一些變量,并不是需要所有的變量,不需要重新寫一個Form子類出來,有好幾種方法:

from django import newforms as formsfrom mysite.myapp.models import Personclass PersonForm(forms.ModelForm):    class Meta:        model = Person        exclude = ('middle', )class PersonForm(forms.ModelForm):    class Meta:        model = Person        fields = ('first', 'last')

這樣一來,忽略的變量就不會被save方法保存,所以忽略它時要確保DB中的定義是 null=True的,否則會報錯。

有時候,還需要重寫forms層里的Field子類,驗證和顯示特定的變量,如下重新定義了first字段的長度

class PersonForm(forms.ModelForm):     first = forms.CharField(max_length=10)     class Meta:         model = Person

關于“關系表單變量” relationship form fields

  • ModelChoiceField -- ForeignKey
  • ModelMultipleChoiceField -- ManyToManyField

還記得嗎?當時Model定義外鍵和多對多關系的時候,使用了 limit_choices_to參數, 其實等效的方法可以在表單層變量里自定義一個 queryset 參數, 用來接收一個 特定的 QuerySet 對象, 如下例子Person模型有一個指向其他Person對象的沒有限制的父ForeignKey:

class PersonForm(forms.ModelForm):    class Meta:        model = Personclass SmithChildForm(forms.ModelForm):    parent = forms.ModelChoiceField(queryset=Person.objects.filter(last='Smith'))    class = Meta:        model = Person

2.1.4 繼承表單

跟繼承模型一樣

from django import newforms as formsclass PersonForm(forms.Form):    first = forms.CharField()    last = forms.CharField()class Person2Form(forms.Form):    first = forms.CharField()    last = forms.CharField()class AgedPersonForm(PersonForm):    age = forms.IntergerField()class MixedPerson(PersonForm, PersonForm2):    # mixed extends

2.2 填寫表單

Django的表單庫中有2種表單

  • 綁定的 bound, 和數據有關系
  • 沒綁定的 unbound, 沒有數據

表單有一個特性, 可以隨便往表單的數據字典里添加額外的鍵值對, 表單會自動無視那些和它們定義無關的輸入

from mysite.myapp.forms import PersonFormdef process_form(request):    post = request.POST.copy()    form = PersonForm(post)

還可以創建一個雖然未綁定,但是模板打印時載入顯示了初始值的表單, 這個命名構造函數參數 initial 是一個字典

每個表單變量也都有一個類似的參數,允許指定它自己的默認值,不過如果有沖突的話, 表單級的 initial 會覆蓋變量級的

from django import newforms as formsfrom django.shotcuts import render_to_responseclass PersonForm(forms.Form):    first = forms.CharField()    last = forms.CharField(initial='Smith')#表單定義時,變量級initial參數    middle = forms.CharField()def process_form(request):    if not reuqest.POST:        form = PersonForm(initial={'first':'John'}) #創建表單實例時, 表單級initial參數,這里如果也定義了last, 則會覆蓋上面的Smith        return render_to_response('myapp/form.html', {'form':form})

使用實例層initial參數的好處在于它的值可以在表單創建的時候才被構造出來, 這樣一來,你可以引用在表單或是模型定義的時候還不知道的信息,特別是請求對象里的信息,看下面的例子

from django.shotcuts import get_object_or_404, render_to_responsefrom mysite.myapp.models import Person, PersonForm# Views's URL /person/<id>/children/adddef add_relative(request, **kwargs):    if not request.POST:        relative = get_object_or_404(Person, pk=kwargs['id']        form = PersonForm(initial={'last': relative.last})        return render_to_response('person/form.html', {'form':form})

這例子中 parent 的 last 值是后來得到的,通過 initial 賦給form, 孩子自動填寫好父親的姓氏

http://m.survivalescaperooms.com/ganiks/p/django-template-and-forms.html

2.3 驗證和清理

要讓表單運行驗證程序,可以顯式使用 is_valid 方法

if request.POST:    form = PersonForm(request.POST)    if form.is_valid:        new_person = form.save()        ... ...

執行完驗證后,表單對象會得到兩個新屬性“之一”:

  • errors -- 包含錯誤信息的字典
  • cleaned_data -- 原來綁定到表單的值的干凈版本
  • 干凈數據意義在于, 輸入的數據需要規范化 --- 從一種或多種可能的輸入格式轉換為一個統一的輸出格式,以方便驗證和數據庫存儲
  • 因為 request.POST 中存儲的格式一般都是字符串, 經過干凈之后
  • 數字變量的字符串 -- int、long
  • 日期變量的字符串 -- datetime

2.4 顯示表單

每個Django表單變量都知道自己在HTML標簽里要怎么顯示, 這種行為是通過 widget 實現的(后面介紹)

first = forms.CharField(max_length=100, required=True)<tr>  <th>    <label for="id_first">First:</label>  </th>  <td>    <input id="id_first" type="text" name="first" maxlength="100" />  </td></tr>
pf = PersonForm(auto_id=False, label_suffix='')<tr>  <th>    <label>First</label>  </th>  <td>    <input type="text" name="first" maxlength="100" />  </td></tr>
pf = PersonForm(auto_id='%s_id', label_suffix='?')<tr>  <th>    <label for="first_id">First?</label>  </th>  <td>    <input id="first_id" type="text" name="first" maxlength="100" />  </td></tr>

2.4.1 顯示全部表單

打印表單有多重方法

  • as_table 默認
  • as_ul
  • as_p

2.4.2 逐個顯示表單

2.4.3 Widget

每個Django表單變量都知道自己在HTML標簽里要怎么顯示, 這種行為是通過 widget 實現的, 這個widget子類(比如TextInput)接受了一個 attrs字典,能直接映射到HTML標簽的屬性上去。

    middle = forms.CharField(max_length=100,        widget=forms.TextInput(attrs={'size':3})<input id="id_middle" maxlength="100" type="text" name="middle" size="3" />

2.4.4 重寫一個變量的默認widget

來自定義一個widget LargeTextarea, 默認擁有 40行和100列

forms.py

from django import newforms as formsclass LargeTextareaWidget(forms.Textarea):    def __init__(self, *args, **kwargs):        kwargs.setdefault('attrs', {}).update({'rows':40, 'cols':100})        super(LargeTextareaWidget, self).__init__(*args, **kwargs))

這里的 setdefault對字典用到一個技巧,在給定的鍵存在情況下回返回現有的值, 若給定的鍵不存在,則返回提供的值;
用在這里,是確保 kwargs 關鍵字參數字典一定共用 attrs 字典, 不管原來的構造函數參數是什么, 可以 update 來更新attrs字典添加我們需要的默認值。

views.py

from django import newsforms as formsfrom mysite.myapp.forms import LargeTextareaWidgetclass ContentForm(forms.Form):    name = forms.CharField()    markup = forms.ChoiceField(choices=[('markdown', 'Markdown'),('textile', 'Textile')])    text = forms.Textarea(widget=LargeTextareaWidget)

是不是還有優化空間?
Django就是Python, 有需要的時候, 很容易把各種類和對象替換出去, 從而達到更靈活的自定義。

forms.py

from django import newforms as formsclass LargeTextareaWidget(forms.Textarea):    def __init__(self, *args, **kwargs):        kwargs.setdefault('attrs', {}).update({'rows':40, 'cols':100})        super(LargeTextareaWidget, self).__init__(*args, **kwargs))class LargeTextarea(forms.Field):    widget = LargeTextareaWidget

現在可以更方便的使用這個自定義的widget
views.py

from django import newsforms as formsfrom mysite.myapp.forms import LargeTextareaWidgetclass ContentForm(forms.Form):    name = forms.CharField()    markup = forms.ChoiceField(choices=[('markdown', 'Markdown'),('textile', 'Textile')])    #text = forms.Textarea(widget=LargeTextareaWidget)    text = LargeTextarea()

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 桃江县| 昆山市| 新乡县| 图们市| 张家口市| 遂昌县| 红原县| 通河县| 淮南市| 二手房| 余姚市| 伊通| 石景山区| 黄骅市| 子洲县| 门头沟区| 贡觉县| 鹿泉市| 涞源县| 曲水县| 宜章县| 石门县| 湾仔区| 胶州市| 桃江县| 信丰县| 郧西县| 翁源县| 蓬溪县| 康马县| 延川县| 太白县| 武功县| 鹤岗市| 东兰县| 龙岩市| 林芝县| 禄丰县| 介休市| 高碑店市| 海安县|