本人未專門學(xué)過前端后端知識,只是一知半解,這篇文章主要作為扒源代碼的思路,具體細(xì)節(jié)并未詳細(xì)介紹?。?!
Blog搭建
博客系統(tǒng)使用python編寫,基于Django和clean-blog前段框架編寫。
本文主要是修改DCblog并通過源碼進(jìn)行階段性掃盲?。?!
DCblog app
查看urls.py文件
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^$', views.index, name='index'),
url(r'^about/', views.about_view, name='about'),
url(r'^article/', include('article.urls'), name='article'),
url(r'^tag/', include('tag.urls'), name='tag'),
url(r'^author/', include('author.urls'), name='author'),
]
urlpatterns += staticfiles_urlpatterns()
handler404 = 'dcblog.views.page404'
handler500 = 'dcblog.views.page500'
下面主要對這幾個url進(jìn)行介紹
url(r'^$', views.index, name='index'),
這兒根目錄調(diào)用的是article.views.index,內(nèi)容如下:
'''
def index(request):
paginator = Paginator(Article.objects.all(), 10)#實例化一個分頁對象
page = request.GET.get('page')#獲取頁碼
try:
articles = paginator.page(page)#獲取某頁對應(yīng)的記錄
except PageNotAnInteger:
articles = paginator.page(1)#如果頁碼不是整數(shù),取第一頁
except EmptyPage:
articles = paginator.page(paginator.num_pages)#如果頁碼太大,沒有相應(yīng)記錄,取最后一頁
return render(request, 'home.html', context={
'articles': articles
})
'''
打開home.html,里面內(nèi)容介紹如下:
首先介紹Django的模板繼承,也就是
{% extends 'base.html' %}
這兒繼承的是base.html模板,查看base.html模板就能發(fā)現(xiàn),這是博客的骨架。打開base.html,如下圖:

這兒大家就可以根據(jù)自己的需要修改文字或者是圖片,除了base.html文件中出現(xiàn)的文字,其他的都在dcblog/settings.py文件的DCBLOG_CONFIG中。
下面回到home.html文件中。在繼承base.html模板后,home.html繼續(xù)做填充,填充方法如下:
{% extends "master.html" %}
{% block content1 %}
content1里填充的內(nèi)容
{% endblock %}
這兒填充的內(nèi)容主要是顯示頁碼內(nèi)的文章和跳轉(zhuǎn)頁碼。
具體細(xì)節(jié)可以看代碼注釋
url(r'^about/', views.about_view, name='about')
這兒調(diào)用的是about_view函數(shù),代碼如下:
def about_view(request):
return render(request, 'about.html')
這兒沒什么好說的,打開about.html文件。這兒依然是使用繼承模板,然后發(fā)現(xiàn)如下代碼:
{% extends 'base.html' %}
{% block header_id %}tag-heading{% endblock %}
{% block header_title %}一技破萬法{% endblock %}
{% block header_subtitle %} 生活不止眼前的茍且, 還有詩和遠(yuǎn)方. {% endblock %}
{% block background-image %}{{ SITE_ABOUT_BACKGROUND }}{% endblock %}
{% block content %}
extend就是繼承父模板,然后下面進(jìn)行復(fù)寫、填充。其中block是在子模版中可能會被覆蓋掉的位置。在上面的例子中,block標(biāo)簽定義了三個可以被子模版內(nèi)容填充的block,分別是 header_title 、header_subtitle和background-image。
{% extends 'base.html' %}
{% block header_id %}tag-heading{% endblock %}
{% block header_title %}一技破萬法{% endblock %}
{% block header_subtitle %} 生活不止眼前的茍且, 還有詩和遠(yuǎn)方. {% endblock %}
{% block background-image %}{{ SITE_ABOUT_BACKGROUND }}{% endblock %}
{% block content %}
下面就是分塊填寫文字和鏈接,應(yīng)該都能看懂了。
url(r'^article/', include('article.urls'), name='article'),
url(r'(?P<article_id>[0-9]+)/$', views.detail, name='detail'),
首先介紹一下Django中的URL模塊
Django處理請求的方式
1) Django通過URLconf模塊來進(jìn)行判斷。通常情況下,這就是ROOT_URLCONF配置的價值,但是如果請求攜帶了一個urlconf的屬性(通常被中間件設(shè)置),那么這個被攜帶的urlconf將會替代ROOT_URLCONF的配置。
2) Django會調(diào)用Python模塊并尋找各種urlpatterns。這是一個屬于django.conf.urls.url()實例的python列表。
3) Django會遍歷每個URL pattern,自上而下,并且選取收割匹配請求URL的pattern。
4) 一旦匹配某個url pattern的正則表達(dá)式,Django將導(dǎo)入并調(diào)用相關(guān)的view(這是一個簡單的python函數(shù),或者是一個class-based view)
這個view將會傳遞下列參數(shù):
- 一個HttpRequest的實例
- 如果匹配了URL中一個no named group,那么參數(shù)將會按根據(jù)URL中的位置一一對應(yīng)
- 如果匹配了URL中一個named group,且參數(shù)傳遞是通過named group來匹配的,那么參數(shù)將會被指定的kwargs代替。
5) 如果沒有任何一個正則表達(dá)式被匹配,那么Django會拋出異常,并報錯。
URL中的named group
URL可以通過named group方式傳遞指定參數(shù),語法為: (?P<name>pattern), name 可以理解為所要傳遞的參數(shù)的名稱,pattern代表所要匹配的模式。例如:
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
那么year,month將會對應(yīng)views傳遞過來的year,month的值,而后面緊跟的則代表正則表達(dá)匹配的模式。
- URL的反向解析
通常來說在處理完一個表單之后,網(wǎng)頁會發(fā)生跳轉(zhuǎn)。通常寫URL我們都避免硬編碼,這樣不方便后期的調(diào)整。通常我們需要從URL獲取兩種內(nèi)容,最主要是view能夠通過URL獲取一些標(biāo)識并處理,另一些信息則是傳遞過來的參數(shù)。
Django提供了一種解決方案,URL mapper是與URL設(shè)計一一對應(yīng)。你可以通過URLconf來實現(xiàn),并反向使用它。例如,
? 由用戶通過瀏覽器發(fā)起URL請求,調(diào)用view,并將URL中的參數(shù)傳遞給view
? 通過view并附上相應(yīng)參數(shù),找到相應(yīng)匹配的URL。
后者我們稱之為對URLs的反向解析。反向解析的例子,
url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
下面對于這個鏈接進(jìn)行解析一下:
當(dāng)在home.html中點擊文章時,會跳轉(zhuǎn)到文章界面,其中跳轉(zhuǎn)的路徑為:{% url 'article:detail' article.id%}。假設(shè)點擊最上面一篇文章,地址為:http://x.x.x.x/article/12/,也就是article.id=12,然后跳轉(zhuǎn)到detail函數(shù):
def detail(requests, article_id):
article = get_object_or_404(Article, pk=article_id)
# article.content = markdown.markdown(article.content, extensions=[
# 'markdown.extensions.extra',
# 'markdown.extensions.codehilite',
# 'markdown.extensions.toc'
# ])
tags = article.tag.all()
return render(requests, 'article_detail.html', context={
'article': article,
'tags': tags
})
介紹函數(shù): article = get_object_or_404(Article, pk=article_id)
用特定查詢條件獲取某個對象,成功則返回該對象,否則引發(fā)一個 Http404。
get_object_or_404(klass, *args, **kwargs)
參數(shù):
-
klass
接受一個 Model 類,Manager 或 QuerySet 實例,表示你要對該對象進(jìn)行查詢。 -
kwargs
查詢條件,格式需要被 get() 和 filter() 接受。
這兒將所有的標(biāo)簽(article和tags)傳遞到article_detail.html代碼中,然后在里面調(diào)用。
打開article_detail.html代碼,可以看到如下幾部分:
- 標(biāo)簽頁跳轉(zhuǎn):顯示所有tags,點擊跳轉(zhuǎn)到標(biāo)簽頁即tags。
- 編輯文章:只有登錄了才能有這一個選項,點擊跳轉(zhuǎn)到edit函數(shù),
url(r'(?P<article_id>[0-9]+)/edit$', views.edit, name='edit'),
這兒就是編輯文章所對應(yīng)的url,先進(jìn)入edit函數(shù)看一下:
@login_required(login_url=reverse_lazy('author:login'))
def edit(request, article_id):
article = get_object_or_404(Article, pk=article_id)
if article.author != request.user and request.user.is_superuser:
return HttpResponseForbidden(render_to_response('error.html', {
'status_code': 403,
'message': 'Forbidden :('
}))
form = ArticleForm(request.POST or None, instance=article)
if request.method == 'POST' and form.is_valid():
form.save()
return HttpResponseRedirect(reverse_lazy('article:detail', kwargs={
'article_id': form.instance.id
}))
context={
'form': form,
'header_id': 'tag-heading',
'title': '編輯文章',
'subtitle': form.instance.title,
'background': form.instance.background or settings.DCBLOG_CONFIG.get('SITE_ARTICLE_BACKGROUND'),
'submit': '保存編輯'
}
return render(request, 'generic_form.html', context=context)
這兒首先讀取article,然后判斷登錄的user是不是文章作者,只有文章作者才能修改文件。非文章作者返回值如下:

往下接著讀代碼,這兒添加一個表單
表單內(nèi)容為:
<tr><th><label for="id_title">標(biāo)題:</label></th><td><input type="text" name="title" value="ff" class="form-control" placeholder="標(biāo)題" maxlength="100" required id="id_title"></td></tr>
<tr><th><label for="id_background">背景圖片:</label></th><td><input type="text" name="background" class="form-control" placeholder="背景URL, 默認(rèn) /static/img/article-bg.png" maxlength="500" id="id_background"></td></tr>
<tr><th><label for="id_tag_list">Tag list:</label></th><td><input type="text" name="tag_list" value="sddf" class="form-control" placeholder="Tags" id="id_tag_list"></td></tr>
<tr><th><label for="id_content">正文:</label></th><td><textarea name="content" cols="40" rows="10" class="form-control" placeholder="markdown正文" row="20" id="id_content">
df</textarea></td></tr>
代碼理解后續(xù)補上
form = ArticleForm(request.POST or None, instance=article)
if request.method == 'POST' and form.is_valid():
form.save()
return HttpResponseRedirect(reverse_lazy('article:detail', kwargs={
'article_id': form.instance.id
}))
然后將參數(shù)傳遞給generic_form.html代碼
{% extends "base.html" %}
{% block head %}
{{ block.super }}
<link rel="stylesheet" href="/static/css/hux-blog.min.css">
{% endblock %}
{% block background-image %}{% spaceless %}
{% if background %}
{{ background }}
{% else %}
{{ SITE_FORM_BACKGROUND }}
{% endif %}
{% endspaceless %}{% endblock %}
{% if header_id %}
{% block header_id %}{{ header_id }}{% endblock %}
{% endif %}
{% block header_title %}{{ title }}{% endblock %}
{% block header_subtitle %}{{ subtitle }}{% endblock %
在這段代碼中,就是將context中的內(nèi)容顯示出,然后下面就是細(xì)化每個模塊,這兒
調(diào)用form表單,也就是上面表單內(nèi)容,創(chuàng)建四個窗口并輸入。然后創(chuàng)建一個保存編輯按鈕。

url(r'^tag/', include('tag.urls'), name='tag'),
進(jìn)入tag/urls.py函數(shù),可以看到:
app_name = 'tag'
urlpatterns = [
url(r'^$', views.tag_index, name='tag_index'),
]
進(jìn)入views.py函數(shù):
def tag_index(request):
tags = Tag.objects.all()
return render(request, 'tag.html', {'tags': tags})
這兒調(diào)用的是tag.html代碼,進(jìn)入html代碼:
{% extends 'base.html' %}
{% block head %}
{{ block.super }}
<link rel="stylesheet" href="/static/css/hux-blog.min.css">
{% endblock %}
{% block header_title %}標(biāo)簽{% endblock %}
{% block header_subtitle %}
<div id="tag_cloud" class="tags">
{% for tag in tags %}
<a href="#{{ tag.name }}" style="background-color: rgb(0, 133, 161);">{{ tag.name }}</a>
{% endfor %}
</div>
{% endblock %}
{% block background-image %}{{ SITE_TAG_BACKGROUND }}{% endblock %}
這兒就是把title改成標(biāo)簽,然后將所有標(biāo)簽進(jìn)行排列

其中每個標(biāo)簽都帶有herf,分別跳到下面每個標(biāo)簽?zāi)K,下面每個標(biāo)簽?zāi)K都有一個標(biāo)簽名,后面for排列出該標(biāo)簽的文章,點擊文章調(diào)用article:detail article.id顯示文章。
url(r'^author/', include('author.urls'), name='author'),
進(jìn)入author/urls.py中, 總共三個二級url,分別對應(yīng)登錄、注冊、注銷三部分
url(r'^login/', views.login_view, name='login'),
查看login_view函數(shù)
@login_denied
def login_view(request):
form = LoginForm(request.POST or None)
if request.method == 'POST' and form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = User.objects.filter(username=username).first()
if user and user.check_password(password):
login(request, user)
return HttpResponseRedirect(reverse_lazy('index'))
messages.add_message(request, messages.ERROR, '用戶名或密碼錯誤.')
context = {'form': form,
'title': '登陸',
'subtitle': 'login site',
'submit': '登陸'
}
return render(request, 'generic_form.html', context)
這兒調(diào)用LoginForm表單,然后將輸入添加到表單,再進(jìn)行對比,顯示界面由genetic_form.html進(jìn)行顯示,登錄成功之后返回主界面。
url(r'^register/', views.register_view, name='register'),
查看register_view函數(shù)
@login_denied
def register_view(request):
form = RegisterForm(request.POST or None)
if request.method == 'POST' and form.is_valid():
form.save()
return HttpResponseRedirect(reverse_lazy('index'))
context = {
'form': form,
'title': '注冊',
'subtitle': 'register and write',
'submit': '注冊'
}
return render(request, 'generic_form.html', context)
這兒調(diào)用RegisterForm表單,同上!
url(r'^logout/', views.logout_view, name='logout'),
這兒沒什么好講的,就是退出返回到最原始界面。
到這兒基本上就能看懂這個博客的大體架構(gòu)了,具體細(xì)節(jié)部分如果后期還要改再扒?。?!
