Django-博客搭建

本人未专门学过前端后端知识,只是一知半解,这篇文章主要作为扒源代码的思路,具体细节并未详细介绍!!!

Blog搭建

博客系统使用python编写,基于Django和clean-blog前段框架编写。
本文主要是修改DCblog并通过源码进行阶段性扫盲!!!

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进行介绍

url(r'^$', views.index, name='index'),

这儿根目录调用的是article.views.index,内容如下:
'''
def index(request):
paginator = Paginator(Article.objects.all(), 10)#实例化一个分页对象
page = request.GET.get('page')#获取页码
try:
articles = paginator.page(page)#获取某页对应的记录
except PageNotAnInteger:
articles = paginator.page(1)#如果页码不是整数,取第一页
except EmptyPage:
articles = paginator.page(paginator.num_pages)#如果页码太大,没有相应记录,取最后一页
return render(request, 'home.html', context={
'articles': articles
})
'''
打开home.html,里面内容介绍如下:
首先介绍Django的模板继承,也就是

{% extends 'base.html' %}

这儿继承的是base.html模板,查看base.html模板就能发现,这是博客的骨架。打开base.html,如下图:


这儿大家就可以根据自己的需要修改文字或者是图片,除了base.html文件中出现的文字,其他的都在dcblog/settings.py文件的DCBLOG_CONFIG中。
下面回到home.html文件中。
在继承base.html模板后,home.html继续做填充,填充方法如下:

{% extends "master.html" %}
 
{% block content1 %}
    content1里填充的内容
{% endblock %}

这儿填充的内容主要是显示页码内的文章和跳转页码。

具体细节可以看代码注释

url(r'^about/', views.about_view, name='about')

这儿调用的是about_view函数,代码如下:

def about_view(request):
    return render(request, 'about.html')

这儿没什么好说的,打开about.html文件。这儿依然是使用继承模板,然后发现如下代码:

{% extends 'base.html' %}
{% block header_id %}tag-heading{% endblock %}
{% block header_title %}一技破万法{% endblock %}
{% block header_subtitle %} 生活不止眼前的苟且, 还有诗和远方. {% endblock %}
{% block background-image %}{{ SITE_ABOUT_BACKGROUND }}{% endblock %}
{% block content %}

extend就是继承父模板,然后下面进行复写、填充。其中block是在子模版中可能会被覆盖掉的位置。在上面的例子中,block标签定义了三个可以被子模版内容填充的block,分别是 header_title 、header_subtitle和background-image。

{% extends 'base.html' %}
{% block header_id %}tag-heading{% endblock %}
{% block header_title %}一技破万法{% endblock %}
{% block header_subtitle %} 生活不止眼前的苟且, 还有诗和远方. {% endblock %}
{% block background-image %}{{ SITE_ABOUT_BACKGROUND }}{% endblock %}
{% block content %}

下面就是分块填写文字和链接,应该都能看懂了。

url(r'^article/', include('article.urls'), name='article'),
url(r'(?P<article_id>[0-9]+)/$', views.detail, name='detail'),

首先介绍一下Django中的URL模块

  1.  Django处理请求的方式
    

1) Django通过URLconf模块来进行判断。通常情况下,这就是ROOT_URLCONF配置的价值,但是如果请求携带了一个urlconf的属性(通常被中间件设置),那么这个被携带的urlconf将会替代ROOT_URLCONF的配置。
2) Django会调用Python模块并寻找各种urlpatterns。这是一个属于django.conf.urls.url()实例的python列表。
3) Django会遍历每个URL pattern,自上而下,并且选取收割匹配请求URL的pattern。
4) 一旦匹配某个url pattern的正则表达式,Django将导入并调用相关的view(这是一个简单的python函数,或者是一个class-based view)
这个view将会传递下列参数:

  • 一个HttpRequest的实例
  • 如果匹配了URL中一个no named group,那么参数将会按根据URL中的位置一一对应
  • 如果匹配了URL中一个named group,且参数传递是通过named group来匹配的,那么参数将会被指定的kwargs代替。
    5) 如果没有任何一个正则表达式被匹配,那么Django会抛出异常,并报错。
  1.  URL中的named  group
    

URL可以通过named group方式传递指定参数,语法为: (?P<name>pattern), name 可以理解为所要传递的参数的名称,pattern代表所要匹配的模式。例如:

url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),

那么year,month将会对应views传递过来的year,month的值,而后面紧跟的则代表正则表达匹配的模式。

  1. URL的反向解析
    通常来说在处理完一个表单之后,网页会发生跳转。通常写URL我们都避免硬编码,这样不方便后期的调整。通常我们需要从URL获取两种内容,最主要是view能够通过URL获取一些标识并处理,另一些信息则是传递过来的参数。
    Django提供了一种解决方案,URL mapper是与URL设计一一对应。你可以通过URLconf来实现,并反向使用它。例如,
     由用户通过浏览器发起URL请求,调用view,并将URL中的参数传递给view
     通过view并附上相应参数,找到相应匹配的URL。
    后者我们称之为对URLs的反向解析。反向解析的例子,
url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),

下面对于这个链接进行解析一下:
当在home.html中点击文章时,会跳转到文章界面,其中跳转的路径为:{% url 'article:detail' article.id%}。假设点击最上面一篇文章,地址为:http://x.x.x.x/article/12/,也就是article.id=12,然后跳转到detail函数:

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
    })

介绍函数: article = get_object_or_404(Article, pk=article_id)
用特定查询条件获取某个对象,成功则返回该对象,否则引发一个 Http404。

get_object_or_404(klass, *args, **kwargs)

参数:

  • klass
    接受一个 Model 类,Manager 或 QuerySet 实例,表示你要对该对象进行查询。
  • kwargs
    查询条件,格式需要被 get() 和 filter() 接受。
    这儿将所有的标签(article和tags)传递到article_detail.html代码中,然后在里面调用。
    打开article_detail.html代码,可以看到如下几部分:
  1. 标签页跳转:显示所有tags,点击跳转到标签页即tags。
  2. 编辑文章:只有登录了才能有这一个选项,点击跳转到edit函数,
url(r'(?P<article_id>[0-9]+)/edit$', views.edit, name='edit'),

这儿就是编辑文章所对应的url,先进入edit函数看一下:

@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是不是文章作者,只有文章作者才能修改文件。非文章作者返回值如下:



往下接着读代码,这儿添加一个表单
表单内容为:

<tr><th><label for="id_title">标题:</label></th><td><input type="text" name="title" value="ff" class="form-control" placeholder="标题" 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, 默认 /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>

代码理解后续补上

    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
        }))

然后将参数传递给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中的内容显示出,然后下面就是细化每个模块,这儿
调用form表单,也就是上面表单内容,创建四个窗口并输入。然后创建一个保存编辑按钮。


url(r'^tag/', include('tag.urls'), name='tag'),

进入tag/urls.py函数,可以看到:


app_name = 'tag'
urlpatterns = [
    url(r'^$', views.tag_index, name='tag_index'),
]

进入views.py函数:


def tag_index(request):
    tags = Tag.objects.all()
    return render(request, 'tag.html', {'tags': tags})

这儿调用的是tag.html代码,进入html代码:

{% extends 'base.html' %}
{% block head %}
    {{ block.super }}
    <link rel="stylesheet" href="/static/css/hux-blog.min.css">
{% endblock %}


{% block header_title %}标签{% 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改成标签,然后将所有标签进行排列



其中每个标签都带有herf,分别跳到下面每个标签模块,下面每个标签模块都有一个标签名,后面for排列出该标签的文章,点击文章调用article:detail article.id显示文章。

url(r'^author/', include('author.urls'), name='author'),

进入author/urls.py中, 总共三个二级url,分别对应登录、注册、注销三部分

url(r'^login/', views.login_view, name='login'),

查看login_view函数

@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)

这儿调用LoginForm表单,然后将输入添加到表单,再进行对比,显示界面由genetic_form.html进行显示,登录成功之后返回主界面。

url(r'^register/', views.register_view, name='register'),

查看register_view函数

@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)

这儿调用RegisterForm表单,同上!

url(r'^logout/', views.logout_view, name='logout'),

这儿没什么好讲的,就是退出返回到最原始界面。



到这儿基本上就能看懂这个博客的大体架构了,具体细节部分如果后期还要改再扒!!!

fork自基于Django和clean-blog前端框架的博客系统

一技破万法
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,711评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,079评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,194评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,089评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,197评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,306评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,338评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,119评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,541评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,846评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,014评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,694评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,322评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,026评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,257评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,863评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,895评论 2 351