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