Django快速搭建一个网站

Django介绍

参考文档:
Django官方文档 官方文档中文翻译

Django是一个开放源代码的Web应用框架,由Python写成,基于MVC构造。但是在Django中,控制器接受用户输入的部分由框架自行处理,
所以Django里更关注的是模型(Model)、模板(Template)和视图(Views),称为MTV模式。一个Django应用程序的基本目录结构如下:

project_name/
    project_name/
        __init__.py
        settings.py
        urls.py
        *views.py
        wsgi.py
    manage.py
    *static/
        base/
            css/
                bootstrap.min.css
            js/
                bootstrap.min.js
    *templates/
        index.html
        base.html
        app_name/
            show.html
    *app_name/
        __init__.py
        admin.py
        urls.py
        views.py
        models.py
        forms.py
        tests.py

模型(Model),即数据存取层———处理与数据相关的所有事务:如何存取、如何验证有效性、包含哪些行为以及数据之间的关系等.
模板(Template),即表现层 ———处理与表现相关的决定:如何在页面或者其他类型文档中进行显示.
视图(View),即业务逻辑层 ———存取模型及调取恰当模板的相关逻辑,模型与模板之间的桥梁.

Django 如何处理一个请求

当一个用户请求Django站点的一个页面,下面是Django系统决定执行哪个Python代码使用的算法:

  1. Django决定要使用的根URLconf模块。通常,这个值就是ROOT_URLCONF的设置.
  2. Django加载该Python模块并寻找可用的urlpatterns它是django.conf.urls.url()实例的一个Python列表。
  3. Django依次匹配每个URL模式,在与请求的URL匹配的第一个模式停下来。
  4. 一旦其中的一个正则表达式匹配上,Django将导入并调用给出的视图,它是一个简单的Python函数(或者一个基于类的视图)。视图将获得如下参数:
    • 一个HttpRequest 实例。
    • 如果匹配的正则表达式没有返回命名的组,那么正则表达式匹配的内容将作为位置参数提供给视图。
    • 关键字参数由正则表达式匹配的命名组组成,但是可以被django.conf.urls.url()的可选参数kwargs覆盖。
      如果视图返回时调用了模板,调用templates下面的html进行渲染展示。
  5. 如果没有匹配到正则表达式,或者如果过程中抛出一个异常,Django将调用一个适当的错误处理视图。

流程图 0.1

快速搭建一个网站

安装Python和Django

Python 2.7.*版本,Django 1.8.3版本,由于系统的不同,安装过程稍有不同。

网站搭建

新建一个工程

1
django-admin startproject mysite

目录结构如上面所示,然后我们在mysite下面新建一个views.py视图文件,在视图文件中定义我们的视图.
mysite/views.py

1
from django.shortcuts import render


def index(request):
    return render(request, 'index.html')

templates目录下面新建index.html文件.
templates/index.html

1
<html>
<head><title>My First Website!</title></head>
<body><p>Hello World!</p></body>
</html>

需要在settings.py中设置模板的路径.
mysite/settings.py

1
TEMPLATES = [
    {
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
    },
]

urls.py中配置URL访问规则.
mysite/urls.py

1
from django.conf.urls import patterns, url
from . import views


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

启动本地Django服务器运行我们的网站程序.

1
python manage.py runserver 8000

在浏览器中打开localhost:8000会看到我们的欢迎页面.

在工程下面添加一个应用

一个网站可能分为不同的模块,每个模块来实现不同的功能,对于每一个模块我们类比于Django中的APP,每一个APP用来实现不同的功能,使框架低耦合。
新建一个应用:

1
python manage.py startapp app_name

然后在project_name/settings.py中包含这个应用.
settings.py

INSTALLED_APPS = (
    ...,
    'app_name',
)

运行python manage.py startapp sample新建一个名为sample的应用,来展示我们的例子.

URL调度器

官方文档 中文 英文
简洁、优雅的URL模式在高质量的Web应用中是非常重要的细节。Django中为了给一个应用设计URL,需要创建一个Python模块,通常称为URLconf(URL configuration,就是前面的urls.py).
这个模块是纯粹的Python代码,它包含URL模式(简单的正则表达式)到Python函数或类(views.py中的函数或类)的简单映射。
下面是一个简单的例子:
mysite/urls.py

from django.conf.urls import include, url
from . import views
urlpatterns = [
    # url(r'^admin/', include(admin.site.urls)),
    url(r'^$', views.index, name="index"),
    url(r'^sample/', include('sample.urls', namespace="sample")),
]

sample/urls.py

from django.conf.urls import url
from . import views
urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'^([0-9]{2})$', views.show_1, name='show_1'),
    url(r'^(?P<year>[0-9]{4})', views.show_2, name='show_2'),
]
  • 在任何时候,urlpatterns都可以包含其他URLconf模块。这实际上是将包含的URL放置在此处。例如在上面中,把APP中的URLconf包含在ROOT_URLCONF中。
  • 上面的示例中使用简单的正则表达式对URL进行匹配,符合Python的正则表达式语法。例如,可以通过圆括号来捕获URL中的值并以位置参数传递给视图,通过命名正则表达式组(?P<name>pattern),其中name是组的名字,pattern是要匹配的模式,来传递命名参数给视图。
  • 匹配按照顺序从上往下进行,直到匹配到满足的结束。

模板语言

Django的模板系统将页面的设计从Python中分离出来,前台页面只需接收后台视图传递过来的数据,动态地展示页面。
templates/navbar.html

1
<html>
<head><title>{% block title %}{% endblock %}</title></head>
<body>
{% block content %}{% endblock content %}
</body>
</html>

templates/sample/show.html

1
{% extends "navbar.html" %}
{% block title %} Sample Page {% endblock %}
{% block content %}

{% if index %}
    <p>I am sample!</p>
{% else%}
    {% if value|length_is:"4" %}
        <p>The year is {{ value }}</p>
    {% elif value|length_is:"2" %}
        <p>The month is {{ value }}</p>
    {% endif %}
{% endif %}
<p>My name is {{ info.name }}, enrolled in {{ info.enroll }}.</p>
{# I am comments. #}
{% endblock %}

  • {{ variable }} 表示一个变量,当模版引擎遇到一个变量,它将计算这个变量,然后用结果替换掉它本身。变量的命名包括任何字母数字以及下划线 (“_”)的组合。点(“.”) 也在会变量部分中出现,不过它有特殊的含义,当模板系统遇到点(“.”),它将以这样的顺序查询:
    • 字典查询
    • 属性或方法查询
    • 数字索引查询
  • Django自带了大约24个内置的模版标签。可以在内置标签参考手册中阅读全部关于它们的内容。
  • {{ value|length_is:"4" }} 表示一个过滤器,Django提供了大约六十个内置的模版过滤器。你可以在内置过滤器参考手册中阅读全部关于它们的信息。
  • 表示一个单行注释, {% comment %}和{% endcomment %}表示多行注释,之间的内容会被忽略。
  • {% csrf_token %} 是一个跨站请求伪造保护标签,在提交表单中需要添加。
  • {% extends "*.html" %} 表示一个模板继承标签,当模板系统处理这个模板时,首先,它将定位父模板,并用子模板中的内容来替换父模板中的block标签中的内容。

视图模块

一个视图函数,简称视图,是一个简单的Python 函数,它接受Web请求并且返回Web响应。响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. . . 是任何东西都可以。无论视图本身包含什么逻辑,都要返回响应。代码写在哪里也无所谓,只要它在你的Python目录下面。除此之外没有更多的要求了——可以说“没有什么神奇的地方”。为了能够把代码放在某个地方,惯例是把视图放在叫做views.py的文件中,然后把它放到你的项目或者应用目录里。
sample/views.py

from django.shortcuts import render


def index(request):
    return render(request, 'sample/show.html', {
        'index': True
    })

def show_1(request, month):
    return render(request, 'sample/show.html', {
        'value': month
    })

def show_2(request, year):
    info = {'name': 'newbie', 'enroll': year}
    return render(request, 'sample/show.html', {
        'value': year,
        'info': info,
    })

视图模块主要是进行业务逻辑的处理,然后返回一个HttpResponse对象。
主要介绍一下表单。

HTML表单

在HTML中,表单是位于<form>…</form> 之间的元素的集合,它们允许访问者输入文本、选择选项、操作对象和控制等等,然后将信息发送回服务器。
处理表单是一件很复杂的事情。考虑一下Django 的Admin 站点,不同类型的大量数据项需要在一个表单中准备好、渲染成HTML、使用一个方便的界面编辑、返回给服务器、验证并清除,然后保存或者向后继续处理。

Django 的表单功能可以简化并自动化大部分这些工作,而且还可以比大部分程序员自己所编写的代码更安全。

Django 会处理表单工作中的三个显著不同的部分:

  • 准备并重新构造数据
  • 为数据创建HTML 表单
  • 接收并处理客户端提交的表单和数据
    可以手工编写代码来实现,但是Django 可以帮你完成所有这些工作。

在Django中构建一个表单
sample/forms.py

1
from django import forms


class NameForm(forms.Form):
    your_name = forms.CharField(label='Your name', max_length=100, required=True)
    age = forms.IntegerField(initial=0)

表单系统的核心部分是Django的Form类.Django 的模型描述一个对象的逻辑结构、行为以及展现给我们的方式,与此类似,Form 类描述一个表单并决定它如何工作和展现.
就像模型类的属性映射到数据库的属性一样,表单类的字段会映射到HTML 的<input>表单的元素.
表单的字段本身也是类;它们管理表单的数据并在表单提交时进行验证。

templates/sample/form.html

1
{% extends "base.html" %}
{% block title %} Sample Page {% endblock %}
{% block content %}

<form action="{% url 'sample:get_name' %}" method="post">
    {% csrf_token %}
    {{ form }}
    <input type="submit" value="Submit" />
</form>

{% endblock %}

sample/views.py

1
from .forms import NameForm


def get_name(request):
    # if this is a POST request we need to process the form data
    if request.method == 'POST':
        # create a form instance and populate it with data from the request:
        form = NameForm(request.POST)
        # check whether it's valid:
        if form.is_valid():
            name = form.cleaned_data['your_name']
            age = form.cleaned_data['age']
            return render(request, 'sample/success.html', {
                    'name': name,
                    'age': age
                })
    else:
        form = NameForm()
    return render(request, 'sample/form.html', {'form': form})

sample/success.html

1
<html>
    <head><title>Success</title>title></head>
     <body>
        <p>Success!</p>
        <p>Your name is {{ name }}, aged {{ age }}.</p>
        <a href='{% url 'sample:get_name' %}'>返回</a>
     </body>
</html>

建立数据库连接

由于我们需要从数据库中读取我们抓取的热点新闻信息,所以需要连接数据库,这里我们采用MYSQL.
project_name/settings.py中默认的数据库是Python自带的SQLite3,所以我们需要修改一下配置.

settings.py

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', # database engine
        'NAME': 'nust_visual_platform', # schema name
        'USER': 'root', # mysql username
        'HOST': 'localhost', # mysql host
        'PASSWORD': '', # mysql password
        'PORT': '3306'} # mysql port
}

我们需要在MYSQL中新建一个schema,剩下的所有对数据库的操作都不需要我们手动处理,Django会为我们代劳.

新建一个数据库表:

  1. wangyi下面新建models.py模型文件,然后在文件中定义我们的数据库表.

    1
    from django.db import models
    
    
    class WangyiArticle(models.Model):
        docid = models.CharField(primary_key=True, max_length=50)
        votecount = models.IntegerField(default=0)
        content = models.TextField()
        ptime = models.DateTimeField()

具体细节可查看Django提供的全部模型字段的字段选项字段类型的API。

2.运行命令来生成产生数据表的SQL代码.

1
python manage.py makemigrations wangyi

我们可以看到类似下面的信息:

Migrations for 'wangyi':
    0001_initial.py:
        - Create model WangyiArticle

3.在数据库中生成数据表

1
python manage.py migrate wangyi

如果你的数据库中其实已经有这张表存在了,就不要执行SQL去改变数据表,这时需要运行

1
python manage.py migrate wangyi --fake-initial

4.对数据表进行URD操作
对数据表的操作可以在models.py中也可以在views.py中,这里我们只介绍如何在views.py中操作数据表.
遍历数据表:

1
WangyiArticle.objects

对获取的数据进行筛选:

1
WangyiArticle.objects.filter(ptime__lt=today)
                     .filter(mtime__gel=yesterday)
                     .filter(parent_id='')
                     .order_by('-votecount')[:10]

Django的ORM(Object Relational Mapping)功能很强大,具体的其他细节可以参考官方文档

自动分页功能

1. 安装
1
pip install python-pagination
2. 配置

参考官方文档

说明:django1.4开始,TEMPLATE_CONTEXT_PROCESSORS不显示在settings.py文件中,此时需要自己添加
settings.py开头添加

1
import django.conf.global_settings as DEFAULT_SETTINGS

在配置最后添加

1
2
3
4
5
6
7
TEMPLATE_CONTEXT_PROCESSORS = DEFAULT_SETTINGS.TEMPLATE_CONTEXT_PROCESSORS + (
"django.contrib.auth.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"django.core.context_processors.request",
)

3. 修改默认样式

site-packages/pagination/templates/pagination/pagination.html文件复制
your_own_templates/pagination/pagination.html,然后修改这个文件就可以了.

4. 参阅资料

七部教你实现Django网站列表自动分页

Bootstrap

中文文档 英文文档

Bootstrap,来自 Twitter,是目前很受欢迎的前端框架。Bootstrap 是基于 HTML、CSS、JAVASCRIPT 的,它简洁灵活,使得 Web 开发更加快捷,是非专业网站开发人员优雅展示自己成果的利器。
Bootstrap是基于HTML5和CSS3开发的,它在jQuery的基础上进行了更为个性化和人性化的完善,形成一套自己独有的网站风格,并兼容大部分jQuery插件。
Bootstrap中包含了丰富的Web组件,根据这些组件,可以快速的搭建一个漂亮、功能完备的网站。其中包括以下组件:
下拉菜单、按钮组、按钮下拉菜单、导航、导航条、路径导航、分页、排版、缩略图、警告对话框、进度条、媒体对象等。

我们可以很方便的把Bootstrap加入到我们的网站之中,以上面的项目为例。
templates/base.html

1
<html>
    <head>
        <title>{% block title %}{% endblock %}</title>
        {% load staticfiles %}
        <link rel="stylesheet" type="text/css" href="{% static 'base/css/bootstrap.min.css' %}"/>
        <script src="{% static 'base/js/jquery-2.1.4.min.js' %}"></script>
        <script src="{% static 'base/js/bootstrap.min.js' %}"></script>
    </head>
    <body>
        {% block content %}{% endblock content %}
    </body>
</head>

只需要把bootstrap的css文件引入HTML中就可以使用它的CSS样式,但是必须在引入bootstrap.js文件之前先引入jQuery文件才能使用javascript插件。

在这里说一下Django的静态文件
除了由服务器生成的HTML文件外,网页应用一般需要提供其它必要的文件 —— 比如图片文件、JavaScript脚本和CSS样式表 —— 来为用户呈现出一个完整的网站。 在Django中,我们将这些文件称为“静态文件”。
首先在mysite中创建一个static目录.Django将在那里查找静态文件,这与Django是如何在templates中寻找对应的模板文件的方式是一致的.需要在配置文件中设置静态文件查找目录.
settings.py

1
STATIC_URL = '/static/'
STATICFILES_DIRS = (
        os.getcwd() + '/static/',
)

{% load staticfiles %} 从staticfiles模板库加载{% static %} 模板标签。{% static %}模板标签会生成静态文件的绝对URL。
1
<!-- Standard button -->
<button type="button" class="btn btn-default">(默认样式)Default</button>

<!-- Provides extra visual weight and identifies the primary action in a set of buttons -->
<button type="button" class="btn btn-primary">(首选项)Primary</button>

<!-- Indicates a successful or positive action -->
<button type="button" class="btn btn-success">(成功)Success</button>

<!-- Contextual button for informational alert messages -->
<button type="button" class="btn btn-info">(一般信息)Info</button>

<!-- Indicates caution should be taken with this action -->
<button type="button" class="btn btn-warning">(警告)Warning</button>

<!-- Indicates a dangerous or potentially negative action -->
<button type="button" class="btn btn-danger">(危险)Danger</button>

<!-- Deemphasize a button by making it look like a link while maintaining button behavior -->
<button type="button" class="btn btn-link">(链接)Link</button>

E-charts

官方文档

ECharts,缩写来自Enterprise Charts,商业级数据图表,一个纯Javascript的图表库,可以流畅的运行在PC和移动设备上,兼容当前绝大部分浏览器(IE6/7/8/9/10/11,chrome,firefox,Safari等),底层依赖轻量级的Canvas类库ZRender,提供直观,生动,可交互,可高度个性化定制的数据可视化图表。创新的拖拽重计算、数据视图、值域漫游等特性大大增强了用户体验,赋予了用户对数据进行挖掘、整合的能力。

支持折线图(区域图)、柱状图(条状图)、散点图(气泡图)、K线图、饼图(环形图)、雷达图(填充雷达图)、和弦图、力导向布局图、地图、仪表盘、漏斗图、事件河流图等12类图表,同时提供标题,详情气泡、图例、值域、数据区域、时间轴、工具箱等7个可交互组件,支持多图表、组件的联动和混搭展现。

以我们的项目为例,可以很方便的使用Echarts进行数据可视化。
templates/sample/echarts.html

1
{% extends "base.html" %}
{% block title%}ECharts{% endblock %}
{% block content %}
<!-- 为ECharts准备一个具备大小(宽高)的Dom -->
<div id="main" style="height:400px"></div>
<!-- ECharts文件引入 -->
<script src="http://echarts.baidu.com/build/dist/echarts-all.js"></script>
<script type="text/javascript">
// 基于准备好的dom,初始化echarts图表
var myChart = echarts.init(document.getElementById('main'));

var option = {
    tooltip: {
        show: true
    },
    legend: {
        data:['销量']
    },
    xAxis : [
        {
            type : 'category',
            data : ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
        }
    ],
    yAxis : [
        {
            type : 'value'
        }
    ],
    series : [
        {
            "name":"销量",
            "type":"bar",
            "data":{{ data }}
        }
    ]
};

// 为echarts对象加载数据
myChart.setOption(option);
</script>
{% endblock %}

效果如下:
柱状图


1
 <!-- 为ECharts准备一个具备大小(宽高)的Dom -->
<div id="main1" style="height:400px; width: 80%; margin-left: 10%;"></div>
<!-- ECharts文件引入 -->
<script src="http://echarts.baidu.com/build/dist/echarts-all.js"></script>
<script type="text/javascript">
// 基于准备好的dom,初始化echarts图表
option1 = {
    title : {
        text: '某站点用户访问来源',
        subtext: '纯属虚构',
        x:'center'
    },
    tooltip : {
        trigger: 'item',
        formatter: "{a} <br/>{b} : {c} ({d}%)"
    },
    legend: {
        orient : 'vertical',
         x : 'left',
         data:['直接访问','邮件营销','联盟广告','视频广告','搜索引擎']
    },
    toolbox: {
        show : true,
        feature : {
            mark : {show: true},
            dataView : {show: true, readOnly: false},
            magicType : {
                show: true,
                type: ['pie', 'funnel'],
                option: {
                    funnel: {
                        x: '25%',
                        width: '50%',
                        funnelAlign: 'left',
                        max: 1548
                    }
                }
            },
            restore : {show: true},
            saveAsImage : {show: true}
        }
    },
    calculable : true,
    series : [
        {
            name:'访问来源',
            type:'pie',
            radius : '55%',
            center: ['50%', '60%'],
            data:[
                {value:335, name:'直接访问'},
                {value:310, name:'邮件营销'},
                {value:234, name:'联盟广告'},
                {value:135, name:'视频广告'},
                {value:1548, name:'搜索引擎'}
            ]
        }
    ]
};

// 为echarts对象加载数据
var myChart = echarts.init(document.getElementById('main1'));
myChart.setOption(option1);
</script>