首先還是貼一下源代碼地址 https://github.com/goodspeedcheng/sblog
上一篇博客我們介紹了 django 如何在views中使用templates以及一些常用的數據操作,這篇博客將介紹靜態文件的使用、from 應用與自定義
1、靜態文件的使用
鑒於我們上次所看到的界面慘不忍睹,為了不影響心情,先介紹一下如何使用靜態文件美化界面
首先新建static目錄,目錄下新建css/js/img三個目錄
修改seeting.py文件
STATICFILES_DIRS = ( '/home/gs/blog/static', #替換成自己的static 目錄 )
修改blog目錄下 urls.py 添加以下內容
urlpatterns += patterns((''), (r'^static/(?P<path>.*)$', 'django.views.static.serve', {'document_root': '/home/gs/blog/static'} ), )
當然這只是本機測試環境下的使用方法,生產環境這樣部署是不可以的。
2、使用bootstrap美化界面
為了方便,我們使用bootstrap進行界面優化,如果你想自己寫界面,這一步完全可以跳過去
bootstrap 下載地址 http://twitter.github.com/bootstrap/
中文文檔:http://wrongwaycn.github.com/bootstrap/docs/index.html
bootstrap使用非常方便下載解壓后 將其中的css/js/img 目錄中文件分別放入static目錄下相應文件夾就好了,然后修改base.html,在head標簽添加
<link rel="stylesheet" href="/static/css/bootstrap.css"> <link rel="stylesheet" href="/static/css/reset.css"> <link rel="stylesheet" href="/static/css/style.css"> <link rel="stylesheet" href="/static/css/code.css"> <script src="/static/js/modernizr.js"></script> <script src="/static/js/jquery.js"></script>
因為bootstrap需要jquery支持,所以必須要引入jquery ,因為我們使用的html5,使用modernizr會自動檢測不兼容的瀏覽器利用js添加相應的功能。
在body添加
<script src="/static/js/bootstrap.min.js"></script>
現在base.html是這個樣子的

<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title> {% block title %}{% endblock %} </title> <link rel="stylesheet" href="/static/css/bootstrap.css"> <script src="/static/js/modernizr.js"></script> <script src="/static/js/jquery.js"></script> {% block extra_head %} {% endblock %} </head> <body> {% block body %} {% block header %} {# 任何每個頁面都可能修改的文本區域的頁面 #} {% block menu %} {# 你的菜單 (導航欄) 應該包含在這個區塊中. 它是針對站點級的導航, 不是 每個頁面專屬的導航菜單. #} {% endblock %} {% endblock %} <div class="container"> {% block content %} {# 這個區塊用來放置頁面正文內容. 任何頁面正文內容都可能不一樣. 它不 包含任何站點導航, 信息頭, 頁腳, 或其它任何屬於 base 模板的東東. #} <div class="container-fluid"> <div class="row-fluid"> <div class="span9"> {% block article %} {% block article_title %} {% comment %} 用來指定 content 區塊的 "title". 比如 blog 的標題. 也可以用來 包含 content 內的導航 (譯注: 比如提綱), 或其它類似的東東. 大致都是些 頁面中並非主要內容的東東. 我不知道這個區塊是否應該放到 content tag 內, 並且對應於前面建議的 content tag, 是不是還需要一個 main_content 區塊. {% block [section]_menu %} {% block page_menu %} 這是對應於之前建議的 menu 區塊. 用來導航一個章節或頁面. {% endcomment %} {% endblock %} {% block article_content %}{% endblock %} {% endblock %} {% block article_menu %} {% endblock %} {% block comments %} {% endblock %} </div> <div class="span3"> {% block aside %} {% block tags %}{% endblock %} {% endblock %} </div> </div> </div> {% endblock %} {% block footer %} {# 任何每個頁面都可能修改的文本區域的頁腳 #} <p>Thanks for visiting my site! </p> {% endblock %} {% endblock %} </div> <script src="/static/js/bootstrap.min.js"></script> </body> </html>
因為base.html中block越多以后越方便,所以我添加了一些標簽,可以暫時忽略
其中用到了bootstrap的布局,閱讀文檔吧: http://twitter.github.com/bootstrap/scaffolding.html
然后新建一個blog_base.html文件,添加blog中會用到的內容,比如導航欄、搜索框等

{% extends "base.html" %} {% block extra_head %} <style> body { padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */ } </style> {% endblock %} {% block header %} {% block menu %} <div class="navbar navbar-inverse navbar-fixed-top"> <div class="navbar-inner"> <div class="container"> <a class="brand" href="#">BLOG</a> <ul class="nav"> <li class="active divider-vertical"> <a href="{% url bloglist %}">home</a> </li> <li> <a href="#">about</a> </li> <li> <a href="#">contact</a> </li> </ul> </div> </div> </div> {% endblock %} {% endblock %}
修改blog_list.html 文件和blog_show.html文件以適應bootstrap
blog_list.html

{% extends "blog_base.html" %} {% load comments %} {% block title %} blog list {% endblock %} {% block article %} <article class='content-main'> {% for blog in blogs %} <h4><a href="{% url detailblog blog.id %}">{{ blog.caption }}</a></h4> <p class="muted"> {% for tag in blog.tags.all %} <i class="icon-tag"></i> <small>{{ tag }}</small> {% endfor %} </p> {% load markup %} <div>{{ blog.content|markdown:'codehilite' }} </div> <div class="row-fluid"> <div class="span3"> <p class="muted"><i class="icon-time"></i><small> {{ blog.publish_time }}</small></p> </div> <div class="span2 offset7"> <a href="{% url delblog blog.id %}" title="delete"><i class="icon-trash"></i></a> <a href="{% url updateblog blog.id %}" title="edit"><i class="icon-edit"></i></a> {% get_comment_count for blog as comment_count %} <a href="{% url detailblog blog.id %}#cmt" title="comment"><i class=" icon-comment"></i>{{ comment_count }}</a> </div> </div> <hr> {% endfor %} </article> {% endblock %} {% block aside %} <a class="btn" href="{# {% url addblog %} #}"><i class="icon-plus"></i> add new blog</a> {% block tags %} <div class="well"> {% for tag in tags %} <span class="label"><a href="{% url filtrblog tag.id %}">{{ tag }}</a></span> {% endfor %} </div> {% endblock %} {% endblock %}
{% extends "blog_base.html" %} {% load comments %} {% block title %} blog list {% endblock %} {% block article %} <article class='content-main'> {% for blog in blogs %} <h4><a href="{% url detailblog blog.id %}">{{ blog.caption }}</a></h4> <p class="muted"> {% for tag in blog.tags.all %} <i class="icon-tag"></i> <small>{{ tag }}</small> {% endfor %} </p> {% load markup %} <div>{{ blog.content|markdown:'codehilite' }} </div> <div class="row-fluid"> <div class="span3"> <p class="muted"><i class="icon-time"></i><small> {{ blog.publish_time }}</small></p> </div> <div class="span2 offset7"> <a href="{% url delblog blog.id %}" title="delete"><i class="icon-trash"></i></a> <a href="{% url updateblog blog.id %}" title="edit"><i class="icon-edit"></i></a> {% get_comment_count for blog as comment_count %} <a href="{% url detailblog blog.id %}#cmt" title="comment"><i class=" icon-comment"></i>{{ comment_count }}</a> </div> </div> <hr> {% endfor %} </article> {% endblock %} {% block aside %} {% block twitter %} <div id="weibo" class="well"> {% for weibo in weibos %} <p class="text-info">{{ weibo }}</p> <p class="text-success"><small>{{ weibo.publish_time }}</small></p> <hr class="soften"> {% endfor %} </div> {% endblock %} {% block tags %} <div class="well"> {% for tag in tags %} <span class="label"><a href="{% url filtrblog tag.id %}">{{ tag }}</a></span> {% endfor %} </div> {% endblock %} {% endblock %}
其中
<a class="btn" href="{# {% url addblog %} #}"><i class="icon-plus"></i> add new blog</a>
是接下來要說的添加文章的操作
{% for tag in tags %} <span class="label"><a href="{% url filtrblog tag.id %}">{{ tag }}</a></span> {% endfor %}
需要在urls.py文件添加
url(r'^blog/tag/(?P<id>\d+)/$', 'blog_filter', name='filtrblog'),
然后添加view
from sblog.models import Tag def blog_filter(request, id=''): tags = Tag.objects.all() tag = Tag.objects.get(id=id) blogs = tag.blog_set.all() return render_to_response("blog_filter.html", {"blogs": blogs, "tag": tag, "tags": tags})
blog_show.html

{% extends "blog_base.html" %} {% block title %} {{ blog.caption }} {% endblock %} {% block article %} <div class="content"> <article class="content-main"> {% block article_title %} <h2>{{ blog.caption }}</h2> {% endblock %} <p class="muted"> <i class="icon-user"></i><small> {{ blog.author }}</small> <i class="icon-time"></i><small> {{ blog.publish_time }}</small> </p> <section> <div class="blog-content"> {% block article_content %} {{ blog.content }} {% endblock %} </div> </section> <section> <div class="row-fluid post-info"> <div class="span3"> <p> <i class="icon-tag"></i> {% for tag in blog.tags.all %} <small class="muted"> {{ tag }} </small> {% endfor %} </p> </div> <div class="span2 offset7"> <a href="{% url delblog blog.id %}" title="delete"><i class="icon-trash"></i></a> <a href="{% url updateblog blog.id %}" title="edit"><i class="icon-edit"></i></a> <a href="#cmt" title="comment"><i class=" icon-comment"></i></a> </div> </div> <hr> </section> </article> <hr> </div> {% endblock %}
這其中
<section> <div class="row-fluid post-info"> <div class="span3"> <p> <i class="icon-tag"></i> {% for tag in blog.tags.all %} <small class="muted"> {{ tag }} </small> {% endfor %} </p> </div> <div class="span2 offset7"> <a href="{% url delblog blog.id %}" title="delete"><i class="icon-trash"></i></a> <a href="{% url updateblog blog.id %}" title="edit"><i class="icon-edit"></i></a> <a href="#cmt" title="comment"><i class=" icon-comment"></i></a> </div> </div> <hr> </section>
是我們接下來要說的對blog的修改、刪除等操作
3、表單的使用及自定義
通過錢兩部,我們美化了一下界面,現在讓我們來添加功能吧。
要實現添加博客的功能,我們必須要用到表單。
Django帶有一個form庫,稱為django.forms,這個庫可以處理我們本章所提到的包括HTML表單顯示以及驗證。當然我們現在有兩個選擇
- 自己寫,完成表單顯示以及驗證
- 使用django提供的From
這里我們選擇后者,既然我們選擇了django,為什么還要重復的造輪子呢?
Form文檔在此 https://docs.djangoproject.com/en/dev/topics/forms/ 我就不再介紹了,直接說怎么用吧。
首先修改urls.py 文件添加
url(r'^blog/add/$', 'blog_add', name='addblog'),
然后在sblog目錄下新建forms.py文件
from django import forms class BlogForm(forms.Form): caption = forms.CharField(label='title', max_length=100) content = forms.CharField(widget=forms.Textarea)
這里我們只博客的標題和內容
CharField 表示字符類型 當你在本地顯示這個表單的時,
content字段被顯示成`` input type=”text”`` ,而它應該被顯示成<`` textarea`` >。我們可以通過設置* widget* 來修改它
然后新建blog_add.html
1 {% extends "blog_base.html" %} 2 3 {% block title %} 發布文字 {% endblock %} 4 5 6 {% block article %} 7 8 <form action="" method="post"> 9 {% csrf_token %} 10 <div class="field"> 11 <label for="id_caption">Title: </label> 12 {% if form.caption.errors %} 13 <div class="alert alert-error"> 14 {{ form.caption.errors }} 15 </div> 16 {% endif %} 17 {{ form.caption }} 18 </div> 19 <div class="field"> 20 <label for="id_content">Content: </label> 21 {% if form.content.errors %} 22 <div class="alert alert-error"> 23 {{ form.content.errors }} 24 </div> 25 {% endif %} 26 {{ form.content }} 27 </div> 28 <div class="form-actions"> 29 <input class="btn btn-primary" type="submit" value="save and add"> 30 </div> 31 </form> 32 {% endblock %}
添加views
from django.http import HttpResponseRedirect from django.template import RequestContext from sblog.models import Author from sblog.forms import BlogForm def blog_add(request): if request.method == 'POST': form = BlogForm(request.POST) if form.is_valid(): cd = form.cleaned_data title = cd['caption'] author = Author.objects.get(id=1) content = cd['content'] blog = Blog(caption=title, author=author, content=content) blog.save() id = Blog.objects.order_by('-publish_time')[0].id return HttpResponseRedirect('/sblog/blog/%s' % id) else: form = BlogForm() return render_to_response('blog_add.html', {'form': form}, context_instance=RequestContext(request))
使用 form的is_valid()方法,驗證它的數據是否合法,如果一個Form實體的數據是合法的,它就會有一個可用的cleaned_data屬性。 這是一個包含干凈的提交數據的字典。
這里我們默認作者是id=1,當然你也可以自己修改或者根據登錄的session讀取
博客提交后 使用HttpResponseRedirect 跳轉到最新發表的博客頁面
因為我們使用的是post 所以必須在表單后面添加 {% csrf_token %}
然后在視圖中使用 context_instance=RequestContext(request)
現在你會發現我們並沒有使用tags,好吧,現在我們添加 tag標簽功能
首先修改forms.py文件 添加
class TagForm(forms.Form): tag_name = forms.CharField()
然后修改視圖

1 from sblog.forms import TagForm 2 3 def blog_add(request): 4 if request.method == 'POST': 5 form = BlogForm(request.POST) 6 tag = TagForm(request.POST) 7 if form.is_valid() and tag.is_valid(): 8 cd = form.cleaned_data 9 cdtag = tag.cleaned_data 10 tagname = cdtag['tag_name'] 11 for taglist in tagname.split(): 12 Tag.objects.get_or_create(tag_name=taglist.strip()) 13 title = cd['caption'] 14 author = Author.objects.get(id=1) 15 content = cd['content'] 16 blog = Blog(caption=title, author=author, content=content) 17 blog.save() 18 for taglist in tagname.split(): 19 blog.tags.add(Tag.objects.get(tag_name=taglist.strip())) 20 blog.save() 21 id = Blog.objects.order_by('-publish_time')[0].id 22 return HttpResponseRedirect('/sblog/blog/%s' % id) 23 else: 24 form = BlogForm() 25 tag = TagForm(initial={'tag_name': 'notags'}) 26 return render_to_response('blog_add.html', 27 {'form': form, 'tag': tag}, context_instance=RequestContext(request))
for taglist in tagname.split(): Tag.objects.get_or_create(tag_name=taglist.strip())
表示將得到的tag字符串用空格分割開 並刪除多余空格
get_or_create表示首先獲取tag_name 如果存在就不操作,不存在就創建
在blog_add.html 文件合適的位置 添加
<div class="field"> <label for="id_tag">tags</label> {% if tag.tag_name.errors %} <div class="alert alert-error"> {{ tag.tag_name.errors }} </div> {% endif %} {{ tag.tag_name }} </div>
現在刷新 http://127.0.0.1:8080/sblog/blog/add/ 是不是看到tag輸入框了,(添加多個標簽使用空格隔開)
4、更新文章內容
修改urls.py文件 添加
url(r'^blog/(?P<id>\w+)/update/$', 'blog_update', name='updateblog'),
因為更新和添加所需表單內容相同,這里就直接使用blog_add.html 作為update的模板
在views.py添加

def blog_update(request, id=""): id = id if request.method == 'POST': form = BlogForm(request.POST) tag = TagForm(request.POST) if form.is_valid() and tag.is_valid(): cd = form.cleaned_data cdtag = tag.cleaned_data tagname = cdtag['tag_name'] tagnamelist = tagname.split() for taglist in tagnamelist: Tag.objects.get_or_create(tag_name=taglist.strip()) title = cd['caption'] content = cd['content'] blog = Blog.objects.get(id=id) if blog: blog.caption = title blog.content = content blog.save() for taglist in tagnamelist: blog.tags.add(Tag.objects.get(tag_name=taglist.strip())) blog.save() tags = blog.tags.all() for tagname in tags: tagname = unicode(str(tagname), "utf-8") if tagname not in tagnamelist: notag = blog.tags.get(tag_name=tagname) blog.tags.remove(notag) else: blog = Blog(caption=blog.caption, content=blog.content) blog.save() return HttpResponseRedirect('/sblog/blog/%s' % id) else: try: blog = Blog.objects.get(id=id) except Exception: raise Http404 form = BlogForm(initial={'caption': blog.caption, 'content': blog.content}, auto_id=False) tags = blog.tags.all() if tags: taginit = '' for x in tags: taginit += str(x) + ' ' tag = TagForm(initial={'tag_name': taginit}) else: tag = TagForm() return render_to_response('blog_add.html', {'blog': blog, 'form': form, 'id': id, 'tag': tag}, context_instance=RequestContext(request))
其中
for taglist in tagnamelist: blog.tags.add(Tag.objects.get(tag_name=taglist.strip())) blog.save() tags = blog.tags.all() for tagname in tags: tagname = unicode(str(tagname), "utf-8") if tagname not in tagnamelist: notag = blog.tags.get(tag_name=tagname) blog.tags.remove(notag)
作用是將tag與blog關聯,並且去掉原有關聯修改后不關聯的tag 例如blog1 原有tag為1,2 ,3 修改后為2, 3
這里的作用是去除blog1與tag 1的關聯
5、刪除文章
修改urls.py 添加
url(r'^blog/(?P<id>\w+)/del/$', 'blog_del', name='delblog'),
修改views.py 添加
def blog_del(request, id=""): try: blog = Blog.objects.get(id=id) except Exception: raise Http404 if blog: blog.delete() return HttpResponseRedirect("/sblog/bloglist/") blogs = Blog.objects.all() return render_to_response("blog_list.html", {"blogs": blogs})
完成后發現我們並沒有相關的update delete 鏈接
將第二步中的注釋去掉吧 現在刷新 blog show 頁面是否看到了呢
最后源代碼可以在 https://github.com/goodspeedcheng/sblog 可以看一下 希望大家把錯誤的地方提出糾正一下。
謝謝
以上 關於from的內容能在 django book 2 第七章找到
擴展閱讀: https://docs.djangoproject.com/en/1.4/
http://twitter.github.com/bootstrap/index.html
推薦 Django 最佳實踐 - 中文版 https://github.com/brantyoung/zh-django-best-practices/blob/master/readme.rst/
ps: 大四學生求實習 郵箱: cacique1103#gmail.com