項(xiàng)目設(shè)置
? ? ? ?DEBUG 一個(gè)布爾型用來開啟或關(guān)閉項(xiàng)目的debug模式。如果設(shè)置為True,當(dāng)你的應(yīng)用拋出一個(gè)未被捕獲的異常時(shí)Django將會(huì)顯示一個(gè)詳細(xì)的錯(cuò)誤頁(yè)面。當(dāng)你準(zhǔn)備部署項(xiàng)目到生產(chǎn)環(huán)境,請(qǐng)記住一定要關(guān)閉debug模式。永遠(yuǎn)不要在生產(chǎn)環(huán)境中部署一個(gè)打開debug模式的站點(diǎn)因?yàn)槟菚?huì)暴露你的項(xiàng)目中的敏感數(shù)據(jù)。
? ? ?ALLOWED_HOSTS 當(dāng)debug模式開啟或者運(yùn)行測(cè)試的時(shí)候不會(huì)起作用(譯者注:最新的Django版本中,不管有沒有開啟debug模式該設(shè)置都會(huì)啟作用)。一旦你準(zhǔn)備部署你的項(xiàng)目到生產(chǎn)環(huán)境并且關(guān)閉了debug模式,為了允許訪問你的Django項(xiàng)目你就必須添加你的域或host在這個(gè)設(shè)置中。
slug:
????????這個(gè)字段將會(huì)在URLs中使用。slug就是一個(gè)短標(biāo)簽,該標(biāo)簽只包含字母,數(shù)字,下劃線或連接線。我們將通過使用slug字段給我們的blog帖子構(gòu)建漂亮的,友好的URLs。
ForeignKey:
? ? 我們通過related_name屬性指定了從User到Post的反向關(guān)系名。
定制models的展示形式
classPostAdmin(admin.ModelAdmin):
? ? ?list_display = ('title','slug','author','publish','status') ? ? #展示的字段
? ? ?list_filter = ('status','created','publish','author') ? ? #過濾返回結(jié)果
? ? ?search_fields = ('title','body') ? ? #搜索字段列
? ? ? prepopulated_fields = {'slug': ('title',)} ? ? #通過輸入的標(biāo)題來填充slug字段
? ? ? raw_id_fields = ('author',)?
? ? ? date_hierarchy ='publish' ? ?#通過時(shí)間層快速導(dǎo)航的欄
? ? ? ordering = ['status','publish']
查詢集(QuerySet)和管理器(managers)
查詢集(QuerySet)是從你的數(shù)據(jù)庫(kù)中根據(jù)一些過濾條件范圍取回的結(jié)果對(duì)象進(jìn)行的采集
每一個(gè)Django模型(model)至少有一個(gè)管理器(manager),默認(rèn)管理器(manager)叫做objects。你通過使用你的模型(models)的管理器(manager)就能獲得一個(gè)查詢集(QuerySet)對(duì)象。獲取一張表中的所有對(duì)象,你只需要在默認(rèn)的objects管理器(manager)上使用all()方法即可
Django的查詢集(QuerySets)是惰性(lazy)的,它們只會(huì)被動(dòng)的去執(zhí)行。這樣的行為可以保證查詢集(QuerySet)非常有效率。
我們之前提到過,objects是每一個(gè)模型(models)的默認(rèn)管理器(manager),它會(huì)返回?cái)?shù)據(jù)庫(kù)中所有的對(duì)象。但是我們也可以為我們的模型(models)定義一些定制的管理器(manager)。
有兩種方式可以為你的模型(models)添加管理器(managers):你可以添加額外的管理器(manager)方法或者繼承管理器(manager)的查詢集(QuerySets)進(jìn)行修改。第一種方法類似Post.objects.my_manager(),第二種方法類似Post.my_manager.all()。我們的管理器(manager)將會(huì)允許我們返回所有帖子通過使用Post.published。
例:
class PublishedManager(models.Manager):
? ? def get_queryset(self):
? ? ? ? ?return super(PublishedManager, self).get_queryset().filter(status='published')
get_queryset()是返回執(zhí)行過的查詢集(QuerySet)的方法
模型(models)的標(biāo)準(zhǔn)URLs
? ? ? ? ?Django的慣例是給模型(model)添加get_absolute_url()方法用來返回一個(gè)對(duì)象的標(biāo)準(zhǔn)URL。在這個(gè)方法中,我們使用reverse()方法允許你通過它們的名字和可選的參數(shù)來構(gòu)建URLS。
模版
????????Django有一個(gè)強(qiáng)大的模板(templates)語(yǔ)言允許你指定數(shù)據(jù)的如何進(jìn)行展示。它基于模板標(biāo)簽(templates tags),{% load staticfiles %}告訴Django去加載django.contrib.staticfiles應(yīng)用提供的staticfiles模板標(biāo)簽(temaplate tags)。通過加載它,你可以在這個(gè)模板(template)中使用{% static %}模板過濾器(template filter)。通過使用這個(gè)模板過濾器(template filter),你可以包含一些靜態(tài)文件比如說blog.css文件
truncatewords用來縮短內(nèi)容限制在一定的字?jǐn)?shù)內(nèi)
linebreaks用來轉(zhuǎn)換內(nèi)容中的換行符為HTML的換行符
分頁(yè)
Django有一個(gè)內(nèi)置的Paginator類允許你方便的管理分頁(yè)
例:
from django.core.paginator importPaginator, EmptyPage, PageNotAnInteger
def post_list(request):
? ? object_list = Post.published.all()?
? ? paginator = Paginator(object_list,3)# 3 posts in each page
? ? page = request.GET.get('page')
? ? try:?
? ? ? ? ? ?posts = paginator.page(page)
? ? except PageNotAnInteger:# If page is not an integer deliver the first page
? ? ? ? ? posts = paginator.page(1)
? ? except EmptyPage:# If page is out of range deliver last page of results
? ? ? ? ? posts = paginator.page(paginator.num_pages)
? ?return render(request,'blog/post/list.html', {'page': page,'posts': posts})
? ? ? ?現(xiàn)在,我們必須創(chuàng)建一個(gè)模板(template)來展示分頁(yè)處理,它可以被任意的模板(template)包含來使用分頁(yè)。在blog應(yīng)用的templates文件夾下創(chuàng)建一個(gè)新文件命名為pagination.html。在該文件中添加如下HTML代碼:
<div class="pagination">
? ? ? ? <span class="step-links">
????????????????{% if page.has_previous %}
? ? ? ? ? ? ? ? ? ? ? ? <a href="?page={{ page.previous_page_number }}">上一頁(yè)</a>
? ? ? ? ????????{% endif %}
? ? ? ? ? ? ? ? <span class="current">Page {{ page.number }} of {{ ????????????????????????????page.paginator_num_pages }}
????????????????</span>
????????????????{% if page.has_next %}
????????????????????????<a href="?page={{ page.next_page_number }}">下一頁(yè)</a>
????????????????{% endif %}
????????</span>
</div>
為了渲染上一頁(yè)與下一頁(yè)的鏈接并且展示當(dāng)前頁(yè)面和所有頁(yè)面的結(jié)果,這個(gè)分頁(yè)模板(template)期望一個(gè)Page對(duì)象。讓我們回到blog/post/list.html模板(tempalte)中將pagination.html模板(template)包含在{% content %}區(qū)塊(block)中,如下所示:
{% block content %}
{% include "pagination.html" with page=posts %}
{% endblock %}
我們傳遞給模板(template)的Page對(duì)象叫做posts,我們將分頁(yè)模板(tempalte)包含在帖子列模板(template)中指定參數(shù)來對(duì)它進(jìn)行正確的渲染。這種方法你可以反復(fù)使用,用你的分頁(yè)模板(template)對(duì)不同的模型(models)視圖(views)進(jìn)行分頁(yè)處理。
Paginator是如何工作的:
? ? 1.我們使用希望在每頁(yè)中顯示的對(duì)象的數(shù)量來實(shí)例化Paginator類。
? ? 2.我們獲取到page?GET參數(shù)來指明頁(yè)數(shù)
? ? 3.我們通過調(diào)用Paginator的page()方法在期望的頁(yè)面中獲得了對(duì)象。
? ? 4.如果page參數(shù)不是一個(gè)整數(shù),我們就返回第一頁(yè)的結(jié)果。如果這個(gè)參數(shù)數(shù)字超出了最大的頁(yè)數(shù),我們就展示最后一頁(yè)的結(jié)果。
? ? 5.我們傳遞頁(yè)數(shù)并且獲取對(duì)象給這個(gè)模板(template)。
使用Django創(chuàng)建表單
Django提供了兩個(gè)可以創(chuàng)建表單的基本類:
????Form: 允許你創(chuàng)建一個(gè)標(biāo)準(zhǔn)表單
????ModelForm: 允許你創(chuàng)建一個(gè)可用于創(chuàng)建或者更新model實(shí)例的表單
is_valid()方法來驗(yàn)證提交的數(shù)據(jù)。這個(gè)方法會(huì)驗(yàn)證表單引進(jìn)的數(shù)據(jù),如果所有的字段都是有效數(shù)據(jù),將會(huì)返回True。一旦有任何一個(gè)字段是無效的數(shù)據(jù),is_valid()就會(huì)返回False。你可以通過訪問form.errors來查看所有驗(yàn)證錯(cuò)誤的列表。
如果表單數(shù)據(jù)驗(yàn)證通過,我們通過訪問form.cleaned_data獲取驗(yàn)證過的數(shù)據(jù)。這個(gè)屬性是一個(gè)表單字段和值的字典。
使用Django發(fā)送email
使用Django發(fā)送email非常簡(jiǎn)單。首先,你需要有一個(gè)本地的SMTP服務(wù)或者通過在你項(xiàng)目的settings.py文件中添加以下設(shè)置去定義一個(gè)外部SMTP服務(wù)器的配置:
EMAIL_HOST: SMTP服務(wù)地址。默認(rèn)本地。
EMAIL_POSR: SMATP服務(wù)端口,默認(rèn)25。
EMAIL_HOST_USER: SMTP服務(wù)的用戶名。
EMAIL_HOST_PASSWORD: SMTP服務(wù)的密碼。
EMAIL_USE_TLS: 是否使用TLS加密連接。
EMAIL_USE_SSL: 是否使用隱式的SSL加密連接。
from django.core.mail import send_mail
send_mail()方法需要這些參數(shù):郵件主題,內(nèi)容,發(fā)送人以及一個(gè)收件人的列表。通過設(shè)置可選參數(shù)fail_silently=False,我們告訴這個(gè)方法如果email沒有發(fā)送成功那么需要拋出一個(gè)異常。
由于我們需要在email中包含帖子的超鏈接,所以我們通過使用post.get_absolute_url()方法來獲取到帖子的絕對(duì)路徑。我們將這個(gè)絕對(duì)路徑作為request.build_absolute_uri()的輸入值來構(gòu)建一個(gè)完整的包含了HTTP schema和主機(jī)名的url。
post_url = request.build_absolute_url(post.get_absolute_url())
創(chuàng)建一個(gè)評(píng)論系統(tǒng)
{% with %}標(biāo)簽(tag)允許我們分配一個(gè)值給新的變量,這個(gè)變量可以一直使用直到遇到{% endwith %}標(biāo)簽(tag)。
{% with %}模板(template)標(biāo)簽(tag)是非常有用的,可以避免直接操作數(shù)據(jù)庫(kù)或避免多次調(diào)用花費(fèi)較多的方法。
創(chuàng)建自定義的模板標(biāo)簽(template tags)和過濾器(filters)
當(dāng)你需要在你的模板中添加功能而Django模板標(biāo)簽(template tags)的核心設(shè)置無法提供此功能的時(shí)候,自定義模板標(biāo)簽會(huì)非常方便。
創(chuàng)建自定義的模板標(biāo)簽(template tags)
Django提供了以下幫助函數(shù)(functions)來允許你以一種簡(jiǎn)單的方式創(chuàng)建自己的模板標(biāo)簽(template tags):
simple_tag:處理數(shù)據(jù)并返回一個(gè)字符串(string)
inclusion_tag:處理數(shù)據(jù)并返回一個(gè)渲染過的模板(template)
assignment_tag:處理數(shù)據(jù)并在上下文(context)中設(shè)置一個(gè)變量(variable)
模板標(biāo)簽(template tags)必須存在Django的應(yīng)用中。
from django import template
register = template.Library()
from ..models import Post
@register.simple_tag
def total_posts():
????????return Post.published.count()
在使用自定義的模板標(biāo)簽(template tags)之前,你必須使用{% load %}標(biāo)簽在模板(template)中來加載它們才能有效。
@register.inclusion_tag('blog/post/latest_posts.html')
def show_latest_posts(count=5):
latest_posts = Post.published.order_by('-publish')[:count]
return {'latest_posts': latest_posts}
我們通過裝飾器@register.inclusion_tag注冊(cè)模板標(biāo)簽(template tag),指定模板(template)必須被blog/post/latest_posts.html返回的值渲染
這個(gè)函數(shù)返回了一個(gè)字典變量而不是一個(gè)簡(jiǎn)單的值。包含標(biāo)簽(inclusion tags)必須返回一個(gè)字典值,作為上下文(context)來渲染特定的模板(template)。包含標(biāo)簽(inclusion tags)返回一個(gè)字典。
@register.assignment_tag
def get_most_commented_posts(count=5):
return Post.published.annotate(
total_comments=Count('comments')
).order_by('-total_comments')[:count]
聚合了每一個(gè)帖子的評(píng)論總數(shù)并保存在total_comments字段中
過濾器其實(shí)就是Python函數(shù)并提供了一個(gè)或兩個(gè)參數(shù)————一個(gè)是需要處理的變量值,一個(gè)是可選的參數(shù)。它們返回的值可以被展示或者被別的過濾器(filters)處理。
from django.utils.safestring import mark_safe
import markdown
@register.filter(name='markdown')
def markdown_format(text):
return mark_safe(markdown.markdown(text))
為你的blog帖子創(chuàng)建feeds
Django有一個(gè)內(nèi)置的syndication feed框架,可以動(dòng)態(tài)(dynamically)生成RSS或者Atom feeds。
from django.contrib.syndication.views import Feed
from django.template.defaultfilters import truncatewords
from .models import Post
class LatestPostsFeed(Feed):
????????title = 'My blog'
????????link = '/blog/'
????????description = 'New posts of my blog.'
????????def ?items(self):
????????????????return Post.published.all()[:5]
????????def item_title(self, item):
????????????????return item.title
????????def item_description(self, item):
????????????????return ?truncatewords (item.body, 30)
手工渲染字段
{{ form.subject.errors }}
{{ form.subject.label_tag }}
{{ form.subject }}
{{form.non_field_errors}}查找每個(gè)字段的錯(cuò)誤。
{{form.name_of_field.errors}}顯示表單錯(cuò)誤的一個(gè)清單,并渲染成一個(gè)ul
widget
widgets用于指定Django在HTML的<input>元素的表現(xiàn)形式
設(shè)置weidget實(shí)例樣式 利用widget.attrs
save(commit=False)
save()方法接受一個(gè)commit的參數(shù),其值為True或者False。默認(rèn)為True。
如果你聲明 save(commit=False),那么它就會(huì)返回一個(gè)還未保存至數(shù)據(jù)庫(kù)的對(duì)象,這樣的話 你可以用這個(gè)對(duì)象添加一些額外的數(shù)據(jù),然后在用save()保存到數(shù)據(jù)庫(kù)
自定義管理頁(yè)面
Django提供了admin.ModelAdmin類通過定義ModelAdmin的子類,來定義模型在Admin界面的顯示方式.
列表頁(yè)屬性
list_display:顯示字段,可以點(diǎn)擊列頭進(jìn)行排序
list_filter:過濾字段,過濾框會(huì)出現(xiàn)在右側(cè)
search_fields:搜索字段,搜索框會(huì)出現(xiàn)在上側(cè)
list_per_page:分頁(yè),分頁(yè)框會(huì)出現(xiàn)在下側(cè)
添加、修改頁(yè)屬性
fields:屬性的先后順序
fieldsets:屬性分組
fieldsets = [
? ? ? ('basic',{'fields': ['btitle']}),
? ? ? ('more', {'fields': ['bpub_date']}),
]
關(guān)聯(lián)對(duì)象
在一對(duì)多的關(guān)系中,可以在一端的編輯頁(yè)面中編輯多端的對(duì)象,嵌入多端對(duì)象的方式包括表格、塊兩種。 類型InlineModelAdmin:表示在模型的編輯頁(yè)面嵌入關(guān)聯(lián)模型的編輯。子類TabularInline:以表格的形式嵌入。
子類StackedInline:以塊的形式嵌入。
1)打開booktest/admin.py文件,創(chuàng)建AreaStackedInline類。
class AreaStackedInline(admin.StackedInline):
? ? ?model=AreaInfo? ? #關(guān)聯(lián)子對(duì)象
? ? ?extra=2? ? #額外編輯2個(gè)子對(duì)象
2)打開booktest/admin.py文件,修改AreaAdmin類如下:
class? AreaAdmin(admin.ModelAdmin):
? ...
? ? inlines=[AreaStackedInline]
class AreaTabularInline(admin.TabularInline):
? ? ? model=AreaInfo? #關(guān)聯(lián)子對(duì)象
? ? ? extra=2? #額外編輯2個(gè)子對(duì)象
class? AreaAdmin(admin.ModelAdmin):
? ? ...
? ? inlines=[AreaTabularInline
布爾值的顯示
發(fā)布性別的顯示不是一個(gè)直觀的結(jié)果,可以使用方法進(jìn)行封裝
def gender(self):
? ? if self.hgender:
? ? ? ?return '男'
? ?else:
? ? ? return '女'
gender.short_description = '性別'
在admin注冊(cè)中使用gender代替hgender
class HeroInfoAdmin(admin.ModelAdmin):
list_display = ['id', 'hname', 'gender', 'hcontent']