使用 Django 创建一份在线简历

使用 Django 创建一份在线简历

一、开篇

去年十二月的时候,我曾跟着追梦人物的Django博客教程葫芦依样,开发出了一个自己的博客 Black&White,那时候的我对网站的结构,网站运行的模式懵懵懂懂,只会跟着教程一步步做下去,遇到问题去找解决方案的过程也很艰辛,找不到出现问题的关键点,最后成品做了出来,但因为只是模仿,没能力创新,使得最后自己的博客 url 是 demo.lightl.fun/,连二级域名都不会修改。之后几个月因为其他事缠身,也就没继续 Django 的学习。适逢将要毕业,我花了几个月将本科知识全部回顾了一遍,对计算机网络的认识更上一层楼,乘着将要找工作,不如重新实践,利用 Django 创建一份在线简历。

二、设计思路

由于做过的工程太少,很多时候设计思路只是一个方向,具体实现过程会对需求做各种变动,随机应变吧。

简单的设计思路就是,开始一个 Django 项目,开始一个新的简历应用,从网上找到前端界面模板,然后作为 static 文件放到简历应用中,根据模板可以提供的数据输出位置设计模型(数据库),然后生成数据库,存入真实数据,用 Django 提供的数据库接口获得数据,在视图函数中作为参数传给前端界面,再在前端界面中使用模板渲染的方法给传来的数据进行渲染,最后使用 nginx 部署在公网服务器上,实现在线简历功能。

三、具体实现及遇到的问题

具体实现过程中,参考自强学堂-Django 基础教程以及追梦人物的 Django 博客教程。此时的实现,会考虑每一步做的意义以及能实现的效果,同时 Django 已经升级到了 2.0.5,而网上教程多集中在 1.8,有少许区别,参照自强学堂提出的以及 google 可以解决,(同时 Django2.0.5 可以兼容Django1.8创建的项目,但在模型部分有修改)。

先是常规的建立项目,建立应用,添加应用信息到 settings.py,给 view.py 添加一个 index 方法,给 urls.py 配置 url 导向,这里没什么太多可说的。

# JL/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'jianli',
]
# JL/urls.py
from django.contrib import admin
from django.urls import path
from jianli import views as jianli_views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('', jianli_views.index, name='jianli_view'),  # 新版 url 写法更舒服了
]

之后找简历模板,最后选择了简历模板,下载,放入应用的 static 文件夹中,将 index.html 放入 templates 文件夹中,给 html 文件中指向的 css、js 位置进行修改,此时出现了第一个渲染的数据 base_dir,它指向应用的 static 文件夹,如果今后移动该文件夹,只需要修改 base_dir 内容,index.html 就可以正常工作。

# jianli/views.py
from django.shortcuts import render

def index(request):
    base_dir = "../../static/"
    return render(request, 'jianli/index.html', {"base_dir":base_dir})

说来惭愧,理应很早就开始的模型设计一直到后面才做到。我先是根据模板能提供显示的内容,写了一些数据放在视图函数中,然后生成一个字典作为 render 方法参数传递给 html 界面,然后在 html 界面中使用 几个括号 等对数据进行渲染,此时的语法参考模板设计者文档,但奇怪的是,jinja2 提出的很多语法在我这个项目里行不通,例如数字计算,in 语法,当时没想太多,只是让视图函数传递的数据多了很多项,也就是 flag 值,方便我在 html 里面选择性渲染。

有一天晚上,觉得视图函数传递的数据很多项只用一次,数据量总体太庞大,而且很多时候我感觉可以使用 jinja2 的方法进行快捷的处理,比如我可以根据数据 id%2 的结果给出不同的呈现方式,但必须得用 is_single 的 flag 来判断。不胜其烦开始查找资料,才发现 django 默认使用的是 DjangoTemplatesLanguage 而不是 jinja2。惊了,开始安装 jinja2,修改 settings.py 的 templates 项以 jinja2 进行渲染,然后大改 html 文件,使用 %、for—if— 语句、if—xxx–in–list 语句大幅度的减少了渲染量。

# JL/settings.py
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.jinja2.Jinja2',
        'DIRS': [os.path.join(BASE_DIR,'jianli/templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
            'environment':'jianli.jinja2_env.environment'
        },
    },
]
<!-- 部分修改后html元素 -->
<div class="col-md-6 skill-right ">
    <div class="scrollbar scrollbar1">
                    
        <div class="clearfix"></div>
    </div>
    </div>

其实代码写到这里,效果已经足够了,部署在服务器就成了。但数据明文放在视图函数,显得笨拙,传递的字典构造到手都疼,该转移到数据库了。但这是遇到了第二个问题也是最麻烦的问题。很明显的,这些数据的结构是 kv,其中 v 部分亦可以是列表,(简言之就是符合 json 传递),将 value 的列表存于 MySQL 中,要么考虑多表,主表外键连接,要么将列表转为 str 存入 MySQL 主表中,取出来的时候再解回列表。按照这个思路开始了模型的编写。完成了存数据,到了取数据过程,开始复杂,Django 给出的接口返回的数据是 queryset 类,可以通过 db.objects.values() 以字典方式获得数据,然后把刚刚 value 的列表数据再取出来,这个代码量,处理过程还不如直接存数据到 views.py 中,而且这个数据库只有一条数据。

退而求其次,既然需要 json.dumps(list) 和 json.loads(str),那么为什么不直接生成一个 json 文件,直接在 views.py 中 json.load(xx.json) 多好,然后就有了如下的代码,瞬间清爽。列表的循环交给 jinja2 处理。

# jianli/views.py
from django.shortcuts import render

import json
# Create your views here.
def index(request):    
    with open('jianli/data.json','r') as f:
        data = json.load(f)
    dic = {}
    for k,v in data.items():
        dic[k] = v

    return render(request, 'jianli/index.html', dic)

最后开始了部署阶段,继续使用 nginx+gunicorn 的方式部署应用,这时参考使用 Nginx 和 Gunicorn 部署 Django 博客,完全可行,如果一台服务器多个应用,那就写多个配置,都可以监听 80 端口,我对于 Linux 的 socket 文件不是很了解,只能大概的猜测是根据 nginx、guincorn 的方法,底层使用 sockcet 编程的思想接收对网站的访问请求。那么我就可以把 demo.lightl.fun 改成 blog.lightl.fun,多写一个配置即可。这里贴一个 nginx 配置文件怎么写。

# /etc/nginx/sites-available/cv.lightl.fun

server {
    charset utf-8;
    listen 80;
    # 服务的域名为 cv.lightl.fun
    server_name cv.lightl.fun; 

    # 所有URL 带有 /static 的请求均由 Nginx 处理,alias 指明了静态文件的存放目录
    location /static { 
        alias /home/light/sites/fun.lightl.fun/JL/static; 
    }

    # 其它请求转发给 Django 处理。proxy_pass 后面使用了 unix 套接字,其作用是防止端口冲突.
    location / { 
        proxy_set_header Host $host;
        proxy_pass http://unix:/tmp/cv.lightl.fun.socket;
    }
}

四、QA

1、为什么在 Django 中 jinja2 的语法用不了?

因为 Django 默认使用 DTL,需要手动安装 jinja2 并指定,请参考本文第三节。

2、为什么 Django 无法读取 json 文件,出现Expecting property name enclosed in double quotes?

json 文件是严格的键值对,但值可以有多种写法,请注意 json 文件中没有多余的逗号(大部分配置文件都喜欢在列表的最后一项添加逗号,但 json 不可以,影响读取)。

3、为什么 nginx 启动后,访问网页出现 502?

原因很多,总体来说是配置文件没写对,同时也要在服务器上应用内进行一次静态文件收集。(有说是 nginx default 文件的问题,但我没遇到)。

五、沉思

在这个项目中,主要

  • 学到了 Django 框架快速搭建网站的过程,要配置 views.py、urls.py
  • 学到了 Django 中 jinja2 如何进行页面的渲染
  • 学到了怎么使用 nginx+gunicorn 部署服务
  • 学到了怎么使用 Django 的 queryset api 来读取数据库数据
  • 学到了怎么修改 HTML 文件、同时对 bootstrap 有了认识。

同时还有很多不足,例如

  • 需求多变,没有确切的实现过程,耽误了一些时间
  • 没使用到 fabric 自动化部署,下次有机会直接上 fabric

项目地址:halysl/job-cv

Search

    Table of Contents