django 簡易博客開發 3 靜態文件、from 應用與自定義


首先還是貼一下源代碼地址  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是這個樣子的

View Code
<!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中會用到的內容,比如導航欄、搜索框等

View Code
{% 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

 

View Code
{% 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

View Code
{% 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()

 然后修改視圖

blog_add
 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添加

View Code
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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM