本人未专门学过前端后端知识,只是一知半解,这篇文章主要作为扒源代码的思路,具体细节并未详细介绍!!!
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[0-9]+)/$', views.detail, name='detail'),
首先介绍一下Django中的URL模块
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会抛出异常,并报错。
URL中的named group
URL可以通过named group方式传递指定参数,语法为: (?P
url(r'^articles/(?P[0-9]{4})/(?P[0-9]{2})/$', views.month_archive),
那么year,month将会对应views传递过来的year,month的值,而后面紧跟的则代表正则表达匹配的模式。
- 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代码,可以看到如下几部分:
- 标签页跳转:显示所有tags,点击跳转到标签页即tags。
- 编辑文章:只有登录了才能有这一个选项,点击跳转到edit函数,
url(r'(?P[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是不是文章作者,只有文章作者才能修改文件。非文章作者返回值如下:
往下接着读代码,这儿添加一个表单
表单内容为:
代码理解后续补上
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 }}
{% 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 }}
{% endblock %}
{% block header_title %}标签{% endblock %}
{% block header_subtitle %}
{% for tag in tags %}
{{ tag.name }}
{% endfor %}
{% 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前端框架的博客系统