Django+Nginx+uwsgi搭建自己的博客(四)

由于在上篇博文中仍然介绍了相当多的后端部分,导致原定于上篇介绍的前端部分“跳票”到了这篇。在此篇博文中,我将会介绍Users App和主页的前端部分,从而形成我们博客的一个雏形。

在前端部分,我们主要使用前端模板来建立我们的网页。Django提供了默认的模板引擎供我们使用。借助模板引擎,我们可以方便地将服务器的数据显示在页面中,实现前后端的交互。此外,模板的另一个好处是可继承性。借助模板继承,我们可以建立一个父模板,然后在其中填入不同的内容来快速建立不同的页面,从而大大减少了我们的工作量。

前端部分分为App和主页两部分。App的前端主要对应App中的views.py中的各个视图函数,而主页的前端是用于对应myblog/views.py中的视图函数的。

我们首先来建立主页的前端部分。在myblog目录下,建立一个名为templates的文件夹,这里是我们存放模板的目录,我们会把父模板和子模板的目录都放在这里。进入该目录,并在其中再建立一个名为myblog的目录,在这里是我们存放子模板的地方,目录结构如下:

  1. ├── templates  
  2. │   ├── myblog  
  3. │   │   ├── 404.html  
  4. │   │   └── index.html  
  5. │   └── parentTemplate.html  
├── templates
│   ├── myblog
│   │   ├── 404.html
│   │   └── index.html
│   └── parentTemplate.html

我们要在templates目录中建立名为parentTemplate.html的文件作为我们的父模板,代码如下:
  1. <!DOCTYPE html>  
  2. <html lang="zh">  
  3. <head>  
  4.     <meta charset="UTF-8">  
  5.     <title>Cap_Liu的博客</title>  
  6. </head>  
  7. <style type="text/css">  
  8.     body{  
  9.         color: #efd;  
  10.         background: #F3F8C5;  
  11.         margin:7px;  
  12.     }  
  13.     h1{  
  14.         padding: 2em;  
  15.         background: #675;  
  16.     }  
  17.     h2{  
  18.         color: #000000;  
  19.         margin-top:2em;  
  20.         text-align: center;  
  21.     }  
  22.     p{  
  23.         margin:1em 0;  
  24.     }  
  25.     .introduce{  
  26.         color: #000000;  
  27.         margin-left: auto;  
  28.         margin-right: 85%;  
  29.     }  
  30.     .list{  
  31.         color: #000000;  
  32.         margin-left: auto;  
  33.         position:relative;  
  34.         left: 20%;  
  35.         top: -20px;  
  36.     }  
  37.     .nav{  
  38.         color: #000000;  
  39.         top: -20px;  
  40.         text-align: right;  
  41.     }  
  42.     .content{  
  43.         color: #000000;  
  44.         top: -20px;  
  45.     }  
  46.     .content p{  
  47.         text-indent: 5em;  
  48.     }  
  49.     .articlelist{  
  50.         text-align: left;  
  51.                 font-size: 20px;  
  52.     }  
  53.     .articlelistinfo{  
  54.         text-align: left;  
  55.         font-size: 20px;  
  56.     }  
  57.       
  58. </style>  
  59. <body>  
  60. <h1>BetrayArmy的博客</h1>  
  61. <div class="introduce">  
  62. {% block introduce %}  
  63. {% endblock %}  
  64. </div>  
  65. <div class="nav">  
  66. {% block nav %}  
  67. {% endblock %}  
  68. </div>  
  69. <div class="content">  
  70. {% block content %}  
  71. {% endblock %}  
  72. </div>  
  73. </body>  
  74. </html>  
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Cap_Liu的博客</title>
</head>
<style type="text/css">
    body{
        color: #efd;
        background: #F3F8C5;
        margin:7px;
    }
    h1{
        padding: 2em;
        background: #675;
    }
    h2{
        color: #000000;
        margin-top:2em;
		text-align: center;
    }
    p{
        margin:1em 0;
    }
	.introduce{
		color: #000000;
		margin-left: auto;
		margin-right: 85%;
	}
	.list{
		color: #000000;
		margin-left: auto;
		position:relative;
		left: 20%;
		top: -20px;
	}
	.nav{
		color: #000000;
		top: -20px;
		text-align: right;
	}
	.content{
	    color: #000000;
		top: -20px;
	}
	.content p{
		text-indent: 5em;
	}
	.articlelist{
		text-align: left;
                font-size: 20px;
	}
	.articlelistinfo{
		text-align: left;
		font-size: 20px;
	}
	
</style>
<body>
<h1>BetrayArmy的博客</h1>
<div class="introduce">
{% block introduce %}
{% endblock %}
</div>
<div class="nav">
{% block nav %}
{% endblock %}
</div>
<div class="content">
{% block content %}
{% endblock %}
</div>
</body>
</html>
在模板中,使用{% block name %}和{% endblock %}来定义模板的内容块,我们可以在子模板中填写对应块的内容。这个父模板很简单,定义了一些CSS样式以及定义了三个div:个人介绍introduce,导航栏nav,以及内容区content。

然后我们开始编写我们的子模板templates/myblog/index.html。该html是真正的主页,它会继承以上的父模板,并负责将myblog/views.py中的index函数返回的数据显示在上面三个内容块中,代码如下:

  1. <!--templates/myblog/index.html-->  
  2. {% extends "parentTemplate.html" %}  
  3.   
  4. {% block introduce %}  
  5. {% if curruser.username  != "anony" or curruser.username  != "" %}  
  6. <div>  
  7. {% if curruser.logoimage %}  
  8. <img src="{{ curruser.logoimage.url }}" width="64" height="64" />  
  9. {% endif %}  
  10. </div>  
  11. <a href="{% url 'users:userInfo' curruser.username %}">{{ curruser.username }}</a>  
  12. {% endif %}  
  13. {% endblock %}  
  14. {% block nav %}  
  15. {% if curruser.username  == "anony" or curruser.username  == "" %}  
  16. <a href="{% url 'users:userregister' %}">用户注册</a>  
  17. <a href="{% url 'users:userlogin' %}">用户登录</a>  
  18. {% else %}  
  19. 用户:{{ curruser.username }}  
  20. <a href="{% url 'users:logoff' %}">退出登录</a>  
  21. <a href="{% url 'blogs:addblog' %}">写博文</a>  
  22. {% endif %}  
  23. {% endblock %}  
  24. {% block content %}  
  25. <div class="list">  
  26. {% if blog_list %}  
  27.     <ul>  
  28.     {% for blog in blog_list %}  
  29.         <div class="articlelist">  
  30.         <a href="{% url 'blogs:content' blog.id %}">{{ blog.title }}</a>-<a href="{% url 'users:userInfo' blog.auther.username %}">{{ blog.auther }}</a>  
  31.         <div class="articlelistinfo">  
  32.         <span title="阅读次数">阅读 {{ blog.readcount }}</span>  
  33.         <span title="创建时间">{{ blog.createdate|date:"Y-m-d H:i:s" }}</span>  
  34.         </div>  
  35.         </div>  
  36.     {% endfor %}  
  37.     </ul>  
  38. {% else %}  
  39.     <p>No blogs</p>  
  40. {% endif %}  
  41. </div>  
  42. {% endblock %}  
<!--templates/myblog/index.html-->
{% extends "parentTemplate.html" %}

{% block introduce %}
{% if curruser.username  != "anony" or curruser.username  != "" %}
<div>
{% if curruser.logoimage %}
<img src="{{ curruser.logoimage.url }}" width="64" height="64" />
{% endif %}
</div>
<a href="{% url 'users:userInfo' curruser.username %}">{{ curruser.username }}</a>
{% endif %}
{% endblock %}
{% block nav %}
{% if curruser.username  == "anony" or curruser.username  == "" %}
<a href="{% url 'users:userregister' %}">用户注册</a>
<a href="{% url 'users:userlogin' %}">用户登录</a>
{% else %}
用户:{{ curruser.username }}
<a href="{% url 'users:logoff' %}">退出登录</a>
<a href="{% url 'blogs:addblog' %}">写博文</a>
{% endif %}
{% endblock %}
{% block content %}
<div class="list">
{% if blog_list %}
	<ul>
	{% for blog in blog_list %}
		<div class="articlelist">
		<a href="{% url 'blogs:content' blog.id %}">{{ blog.title }}</a>-<a href="{% url 'users:userInfo' blog.auther.username %}">{{ blog.auther }}</a>
		<div class="articlelistinfo">
		<span title="阅读次数">阅读 {{ blog.readcount }}</span>
		<span title="创建时间">{{ blog.createdate|date:"Y-m-d H:i:s" }}</span>
		</div>
		</div>
	{% endfor %}
	</ul>
{% else %}
	<p>No blogs</p>
{% endif %}
</div>
{% endblock %}
这里介绍一下模板语言中的一些关键字:

{% extends "parentTemplate.html" %}:在模板中,使用{% extends 模板名 %}这种关键字来声明该页面继承于哪个模板。若某网页继承了某模板,其就可以修改父模板的block内容,以及使用定义在父模板中的CSS样式。

{% block introduct %}:由于继承了parentTemplate模板,因此这里的block名称要与父模板中的block名称一样,以实现填写对应block内容的目的。

{% if curruser.username  != "anony" or  curruser.username  != "" %}和{% endif %}:模板语言中的条件判断,每个{% if %}必须要有一个{% endif %}与之对应。

在模板中,可以直接使用通过服务器传入的python对象,并访问其方法和属性。curruser即为通过myblog/views.py中的index函数传回的对象,如下所示:

  1. # myblog/views.py  
  2. def index(request):  
  3.     try:  
  4.         username = request.session['username']  
  5.         user = Users.objects.get(username=username)  
  6.     except KeyError:  
  7.         user = Users.objects.get(username='anony')  
  8.     except Users.DoesNotExist:  
  9.         user = Users.objects.get(username='anony')  
  10.     blogList = Blog.objects.filter(draft=False).order_by('title')  
  11.     content = { 'blog_list':blogList,  
  12.                 '<span style="color:#ff0000;">curruser</span>':<span style="color:#ff0000;">user</span>  
  13.                }  
  14.     return render(request, 'myblog/index.html', content)  
# myblog/views.py
def index(request):
    try:
        username = request.session['username']
        user = Users.objects.get(username=username)
    except KeyError:
        user = Users.objects.get(username='anony')
    except Users.DoesNotExist:
        user = Users.objects.get(username='anony')
    blogList = Blog.objects.filter(draft=False).order_by('title')
    content = { 'blog_list':blogList,
                'curruser':user
               }
    return render(request, 'myblog/index.html', content)
在index函数中,通过字典向index.html传递了两个参数:名为curruser的Users类对象和名为blog_list的list对象,而我们可以在html模板中直接访问这两个对象,包括获得其属性、对其进行遍历等操作。若想访问对象的属性,可以通过.运算符来进行。

{% url ‘users:userregister’ [参数名] %}:html中<a>标签或表单action属性中的url地址。该标签与urls.py中的url列表项一一对应,如users:userregister指的是在Users App中的urls.py文件中的名为userregister项,如下所示:

  1. # Users App urls.py  
  2. from django.conf.urls import url,include  
  3. from . import views  
  4. from myblog.views import index  
  5.   
  6. app_name='<span style="color:#ff0000;">users</span>'  
  7. urlpatterns = [  
  8.     url(r'^$', index, name='index'),  
  9.     url(r'^userregister/$',views.userregister,name='<span style="color:#ff0000;">userregister</span>'),  
  10.     url(r'^userlogin/$',views.userlogin,name='userlogin'),  
  11.     url(r'^loginResult/(?P<info>.*)$',views.loginResult,name='loginResult'),  
  12.     url(r'^registerResult/(?P<info>.*)$',views.registerResult,name='registerResult'),  
  13.     url(r'^logoff/$',views.logoff,name='logoff'),  
  14.     url(r'^userinfo/(?P<username>.*)$',views.userInfo,name='userInfo')  
  15. ]  
  16. # 红字即为users:userregister的来源  
# Users App urls.py
from django.conf.urls import url,include
from . import views
from myblog.views import index

app_name='users'
urlpatterns = [
    url(r'^$', index, name='index'),
    url(r'^userregister/$',views.userregister,name='userregister'),
    url(r'^userlogin/$',views.userlogin,name='userlogin'),
    url(r'^loginResult/(?P<info>.*)$',views.loginResult,name='loginResult'),
    url(r'^registerResult/(?P<info>.*)$',views.registerResult,name='registerResult'),
    url(r'^logoff/$',views.logoff,name='logoff'),
    url(r'^userinfo/(?P<username>.*)$',views.userInfo,name='userInfo')
]
# 红字即为users:userregister的来源
若url后面有参数,则直接加在url名称后即可。

{% for blog in blog_list %}和{% endfor %}:for循环操作。该循环会遍历blog_list中的每个元素,并将其相关信息显示在网页中。由于Blog的部分还没有写,因此之前的index函数中的blogList和页面中的这个for循环可以先跳过。

另一个404.html的模板就相对简单多了,如下所示:

  1. <!-- 404.html -->  
  2. {% extends "parentTemplate.html" %}  
  3. {% block content %}  
  4. <div class="list">  
  5. <p>页面未找到!</p>  
  6. <p><a href="{% url 'index' %}">返回首页</a></p>  
  7. </div>  
  8. {% endblock %}  
<!-- 404.html -->
{% extends "parentTemplate.html" %}
{% block content %}
<div class="list">
<p>页面未找到!</p>
<p><a href="{% url 'index' %}">返回首页</a></p>
</div>
{% endblock %}

现在,主页的前端页面已经建立完成,我们可以如法炮制,建立Users App的前端页面。

我们回到users文件夹下,同样建立templates目录,然后可以将之前建立好的parentTemplate.html拷贝过来,重命名为userTemplate.html;然后建立users目录,此时users/templates目录结构如下:

  1. ├── users  
  2. │   ├── loginResult.html  
  3. │   ├── registerResult.html  
  4. │   ├── userinfo.html  
  5. │   ├── userlogin.html  
  6. │   └── userregister.html  
  7. └── userTemplate.html  
├── users
│   ├── loginResult.html
│   ├── registerResult.html
│   ├── userinfo.html
│   ├── userlogin.html
│   └── userregister.html
└── userTemplate.html

可以看到,Users App的前端部分共有5个页面,分别对应users/views.py中除了logoff函数外的5个view函数。

首先来看userregister.html,这一页面主要就是显示了用户注册的表单,如图所示:



因此其模板也比较简单:从服务器获得表单对象并将其显示出来:

  1. <!-- userregister.html -->  
  2. {% extends "userTemplate.html" %}  
  3. {% block content %}  
  4. <h3>新用户注册</h3>  
  5. <form action="{% url 'users:userregister' %}" method="post" enctype="multipart/form-data">  
  6. {% csrf_token %}  
  7. {{ form.as_p }}  
  8. <p><input type="submit" value="提交"></p>  
  9. </form>  
  10. {% endblock %}  
<!-- userregister.html -->
{% extends "userTemplate.html" %}
{% block content %}
<h3>新用户注册</h3>
<form action="{% url 'users:userregister' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<p><input type="submit" value="提交"></p>
</form>
{% endblock %}

这里出现了一个新参数:{% csrf_token %},这是Django提供的csrf校验功能,一般来说都要加上,防止跨站伪造请求。此外,由于该表单有文件上传功能,因此enctype要设置为"multipart/form-data"。而form为前一篇博文中介绍的ModelForm,通过as_p方法,在页面中会将表单的每项用<p>标签显示出来。

然后就是registerResult.html,这一页面用于显示注册成功与否:

  1. <!-- registerResult.html -->  
  2. {% extends "userTemplate.html" %}  
  3. {% block content %}  
  4. <h3>{{ result_info }}</h3>  
  5. <a href="{% url 'index' %}" >返回首页</a>  
  6. {% endblock %}  
<!-- registerResult.html -->
{% extends "userTemplate.html" %}
{% block content %}
<h3>{{ result_info }}</h3>
<a href="{% url 'index' %}" >返回首页</a>
{% endblock %}

接下来是userlogin.html与loginResult.html,这两个页面与userregister.html/registerResult.html基本完全相同,因此一块放出来:
  1. <!-- userlogin.html -->  
  2. {% extends "userTemplate.html" %}  
  3. {% block content %}  
  4. <h3>用户登录</h3>  
  5. <form action="{% url 'users:userlogin' %}" method="post">  
  6. {% csrf_token %}  
  7. {{ form.as_p }}  
  8. <p><input type="submit" value="登录"></p>  
  9. </form>  
  10. {% endblock %}  
  11.   
  12. <!-- loginResult.html -->  
  13. {% extends "userTemplate.html" %}  
  14. {% block content %}  
  15. <h3>{{ result_info }}</h3>  
  16. <a href="{% url 'index' %}" >返回首页</a>  
  17. {% endblock %}  
<!-- userlogin.html -->
{% extends "userTemplate.html" %}
{% block content %}
<h3>用户登录</h3>
<form action="{% url 'users:userlogin' %}" method="post">
{% csrf_token %}
{{ form.as_p }}
<p><input type="submit" value="登录"></p>
</form>
{% endblock %}

<!-- loginResult.html -->
{% extends "userTemplate.html" %}
{% block content %}
<h3>{{ result_info }}</h3>
<a href="{% url 'index' %}" >返回首页</a>
{% endblock %}
最后一个页面是userinfo.html,用于显示用户信息:
  1. <!-- userinfo.html -->  
  2. {% extends "userTemplate.html" %}  
  3. {% block content %}  
  4. <h3>用户{{ username }}资料</h3>  
  5. <p>用户名: {{ username }}</p>  
  6. <p>注册时间: {{ registertime|date:"Y-m-d" }}</p>  
  7. <p>生日: {{ birthday|date:"Y-m-d H:i:s" }}</p>  
  8. <p>电子邮件: {{ email }}</p>  
  9. <p><a href="{% url 'index' %}">返回首页</a></p>  
  10. {% endblock %}  
<!-- userinfo.html -->
{% extends "userTemplate.html" %}
{% block content %}
<h3>用户{{ username }}资料</h3>
<p>用户名: {{ username }}</p>
<p>注册时间: {{ registertime|date:"Y-m-d" }}</p>
<p>生日: {{ birthday|date:"Y-m-d H:i:s" }}</p>
<p>电子邮件: {{ email }}</p>
<p><a href="{% url 'index' %}">返回首页</a></p>
{% endblock %}

注意,这里的registertime和birthday由于在Model中均为DateTimeField,因此我们需要用|date的方式告诉前端应将其显示成正确的日期或时间格式,否则会显示不正确。

现在,我们的博客算是有了个基本的雏形,可以在上面注册用户并登录了。然而,如果现在我们注册了一个有头像的用户并登录,我们会发现在主页上并不能显示出用户头像,这是因为我们现在并没有处理静态文件。在下一篇博客中,我将介绍怎样把我们的博客使用uwsgi+nginx的方式部署在本地,这将会是一个大难点,敬请期待~

原文地址:https://www.cnblogs.com/xiaoyaojinzhazhadehangcheng/p/8360452.html