Python - Django Web开发(1)

安装

  1. 先安装Python,从官网下载安装包直接运行即可
  2. 打开Django官网(https://www.djangoproject.com),点击DOWNLOAD页面,根据操作系统选择合适的安装方式。
    1
    py -m pip install Django==5.0.6
  3. 使用命令python -m django --version查看版本号,如有输出即表示安装成功

创建

Django内置一个管理工具django-admin,可以使用它来进行一系列的操作

项目

  1. 使用命令django-admin startproject HelloWorld创建项目
  2. 创建完成后的项目目录结构如下所示:
    1
    2
    3
    4
    5
    6
    7
    8
    .
    |-- HelloWorld -- 项目的容器
    | |-- __init__.py -- 空文件,用于标识Python包
    | |-- asgi.py -- ASGI兼容的Web服务器入口
    | |-- settings.py -- Django项目的所有配置信息
    | |-- urls.py -- Django项目的URL声明即路由信息
    | `-- wsgi.py -- WSGI兼容的Web服务器入口
    `-- manage.py -- 实用的命令行工具,用于和Django项目进行交互

运行

  1. 使用命令py manage.py runserver 0.0.0.0:8000启动项目

模板

创建模板

  1. 在项目/应用目录下创建文件夹templates,在该目录下再创建相关的html模板页面
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    </head>
    <body>
    <h1> {{ Hello }}</h1>
    </body>
    </html>
  2. 模板中的变量使用双括号标识,同时需要修改settings.py文件中的TEMPLATES配置项,添加DIRS配置项,如下所示:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    TEMPLATES = [
    {
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'DIRS': [os.path.join(BASE_DIR, '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',
    ],
    },
    },
    ]
  3. 修改urls.py文件,添加路由信息,如下所示:
    1
    2
    3
    4
    5
    6
    from django.urls import path
    from . import views

    urlpatterns = [
    path('index/', views.index),
    ]
  4. 修改views.py文件,添加视图函数,如下所示:
    1
    2
    3
    4
    5
    6
    7
    from django.shortcuts import render

    def index(request):
    return render(request, 'index.html', {'Hello': 'Hello World!'})
    # context = {}
    # context['Hello'] = 'Hello World!'
    # return render(request, 'index.html', context)

模板标签

  1. 变量
    1
    2
    view: {"HTML变量名" : "views变量名"}
    HTML: {{ HTML变量名 }}
  2. 列表 - 可以使用.索引下标来取出对应的元素
    1
    2
    view: view_list = ["a", "b", "c"]
    HTML: {{ view_list.0 }}
  3. 字典 - 可以使用.键取出对应的值
    1
    2
    view: view_dict = {"a": 1, "b": 2, "c": 3}
    HTML: {{ view_dict.a }}
  4. 过滤器 - 可以在变量被显示前修改它,使用管道字符,且管道字符可以被套接,有些过滤器存在参数且参数跟随冒号之后总是以双引号包含
    1
    2
    3
    4
    5
    6
    7
    8
    9
    view: view_list = "hello world"
    HTML: {{ view_list|first|upper }} - 显示列表第一个元素并大写
    HTML: {{ str|truncatewords:"30"}} - 显示变量str的前30个字符
    HTML: {{ str|truncatechars:"3"}} - 如果包含的字符总个数多于指定的字符数量,后续内容将会被截断,以`...`结尾
    HTML: {{ view_parm|default:"默认值" }} - default为变量提供一个默认值|[0,0.0,False,0j,"",[],(),set(),{},None] = false
    HTML: {{ view_name|length }} - 返回对象的长度,适用于字符串和列表,字典返回键值对数量,集合返回去重后的长度
    HTML: {{ file|filesizeformat }} - 返回文件大小,格式化后显示
    HTML: {{ view_date|date:"Y-m-d" }} - 格式化日期,格式化字符串
    HTML: {{ view_str|safe }} - 将变量标记为安全,不进行转义,可以用来传递HTML代码
  5. 注释
    1
    HTML: {# 注释内容 #}
  6. 条件语句
    1
    2
    view: view_dict = {"a": 1, "b": 2, "c": 3}
    HTML: {% if view_dict.a > 0 %} 条件为真 {% elif %} 条件为假 {% else %} 条件为假 {% endif %}
  7. 循环语句 - 允许我们在一个序列上迭代
    1
    2
    3
    4
    5
    view: view_list = ["a", "b", "c"]
    HTML: {% for item in view_list [reversed] %} {{ item }} {% endfor %} - [reversed]表示倒序

    view: view_dict = {"a": 1, "b": 2, "c": 3}
    HTML: {% for key, value in view_dict.items %} {{ key }}: {{ value }} {% endfor %} - 使用.item方法分别获取键值
    1
    2
    3
    4
    5
    6
    7
    8
    使用`{{ forloog }}`变量获取循环序号
    - `forloop.counter` - 当前循环的索引值
    - `forloop.counter0` - 当前循环的索引值,从0开始
    - `forloop.revcounter` - 当前循环的倒序索引值
    - `forloop.revcounter0` - 当前循环的倒序索引值,从0开始
    - `forloop.first` - 当前循环是否是第一次循环,即第一条数据返回True
    - `forloop.last` - 当前循环是否是最后一次循环,即最后一条数据返回True
    - `forloop.parentloop` - 父循环
    1
    2
    3
    可选{{% empty %}}从句,在循环为空时执行,即in后面的参数布尔为false
    view: view_list = []
    HTML: {% for item in view_list %} {{ item }} {% empty %} 列表为空 {% endfor %}
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    嵌套使用for标签
    {% for athlete in athlete_list %}
    <h1>{{ athlete.name }}</h1>
    <ul>
    {% for sport in athlete.sports_played %}
    <li>{{ sport }}</li>
    {% endfor %}
    </ul>
    {% endfor %}

  8. ifequal/ifnotequal 标签
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    比较两个值,相等时,显示值
    {% ifequal user currentuser %}
    <h1>Welcome!</h1>
    {% endifequal %}

    支持else标签
    {% ifequal section 'sitenews' %}
    <h1>Site News</h1>
    {% else %}
    <h1>No News Here</h1>
    {% endifequal %}
  9. 注释标签
    1
    {# 注释内容 #}
  10. csrf_token标签 - 跨站请求伪造保护
  11. include标签 - 允许在模板中包含其它模板的内容
    1
    {% include "header.html" %}

自定义标签和过滤器

  1. 在应用目录下创建templatetags目录,与templates目录同级
  2. templatetags目录下创建mytags.py文件
  3. 在上述创建的文件中编写对应的代码,并修改settings.py文件中的TEMPLATES选项的配置,添加libraries配置
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    # mytags.py
    from django import template

    register = template.Library() #register的名字是固定的,不可改变

    # settings.py
    TEMPLATES = [
    {
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'DIRS': [BASE_DIR, "/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',
    ],
    "libraries":{ # 添加这边三行配置
    'mytags':'templatetags.mytags' # 添加这边三行配置
    } # 添加这边三行配置
    },
    },
    ]
  4. 利用装饰器@register.filter自定义过滤器,且装饰器的参数最多只能有2个
    1
    2
    3
    @register.filter
    def my_filter(v1, v2):
    return v1 * v2
  5. 利用装饰器register.simple_tag自定义标签
    1
    2
    3
    @register.simple_tag
    def my_tag1(v1, v2, v3):
    return v1 * v2 * v3
  6. 在使用自定义标签和过滤器前,需要在html文件body的最上方导入该py文件
    1
    {% load mytags %}
  7. 使用
    1
    2
    {{ 11|my_filter:22 }}
    {% my_tag1 11 22 33 %}
  8. 语义化标签
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #  在py文件中导入mark_safe
    from django.utils.safestring import mark_safe
    # 定义标签时,使用mark_safe方法,和模板页面中的safe效果一致
    @register.simple_tag
    def my_html(v1, v2):
    temp_html = "<input type='text' id='%s' class='%s' />" %(v1, v2)
    return mark_safe(temp_html)
    # 在html中使用该标签
    {% my_html "zzz" "xxx" %}

静态文件

  1. 在项目根目录下创建statics目录
  2. settings.py文件添加以下配置
    1
    2
    3
    4
    STATIC_URL = '/static/' # 别名
    STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "statics"),
    ]
  3. 在 statics 目录下创建 css 目录,js 目录,images 目录,plugins 目录, 分别放 css文件,js文件,图片,插件
  4. 把 bootstrap 框架放入插件目录 plugins
  5. 在 HTML 文件的 head 标签中引入 bootstrap,此时引用路径中的要用配置文件中的别名 static,而不是目录 statics
    1
    <link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7/dist/css/bootstrap.css">
  6. 在模板中使用需要加入{% load static %}代码
    1
    2
    {% load static %}
    <img src="{% static 'images/logo.png' %}" alt="logo">

模板继承

模板可以使用继承的方式来实现复用,减少冗余内容,网页的头部和尾部内容一般都是一致的,我们就可以通过模板继承来实现复用,父模板中放置可以重复使用的内容,子模板继承父模板的内容,并添加自己的内容

父模板

标签 block...endblock: 父模板中的预留区域,该区域留给子模板填充差异性的内容,不同预留区域名字不能相同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{% block 名称 %} 
预留给子模板的区域,可以设置默认内容
{% endblock 名称 %}


--示例--
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Demo</title>
</head>
<body>
<h1>Hello World!</h1>
<p>Django Demo.</p>
{% block mainbody %}
<p>这里是父模板预设内容</p>
{% endblock %}
</body>
</html>

子模版

标签 extends...endextends: 子模板继承父模板的内容

1
{% extends '父模板名称' %}

标签 block...endblock: 子模板填充父模板预留区域的内容,如果没有设置则使用父模板设置的内容,当然也可以不设置全部为空

1
2
3
4
5
6
7
8
9
10
11
{% block 名称 %}
子模板中填充的内容
{% endblock 名称 %}


--示例--
{%extends "father.html" %}

{% block mainbody %}
<p>继承了 father.html 文件</p>
{% endblock %}

模型

Djagno规定,如果要使用模型,则必须要创建一个App,创建方式如下:
py manage.py startapp [应用名]

数据库

  1. Django支持多种数据库,包括sqllite3,mysql,postgresql,oracle
  2. 先使用对应数据库的方法创建一个数据库,因为ORM无法操作到数据库级别,只能操作到数据表
    1
    2
    -- e.g:mysql创建数据库的方法
    create database 数据库名称 default charset=utf8;

配置

需要在setting.py中找到INSTALLED_APP,在其中添加上创建的app,如下所示:

1
2
3
4
5
6
7
8
9
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01'
]
  1. 模型相关的数据全部放置在HelloWorld/app01/models.py
  2. 上述文件中的类名即代表了数据库的表名,且继承了models.Model
  3. 类里面的字段代表了数据表中的字段,数据类型有CharField(varchar),DateField(datetime),max_length限定长度。

需要修改settings.py文件中DATABASES配置项,修改内容如下所示:

1
2
3
4
5
6
7
8
9
10
11
DATABASES = { 
'default':
{
'ENGINE': 'django.db.backends.mysql', # 数据库引擎
'NAME': 'DjangoDB', # 数据库名称
'HOST': '127.0.0.1', # 数据库地址,本机 ip 地址 127.0.0.1
'PORT': 3306, # 端口
'USER': 'root', # 数据库用户名
'PASSWORD': '123456', # 数据库密码
}
}

运行

1
2
3
py manage.py migrate  # 创建表结构
py manage.py makemigrations [app_name] # 告知Django模型的变更
py manage.py migrate [app_name] # 创建表结构
  1. 表名组成结构:应用名_类名(如:app01_Test)
  2. Django会自动添加一个id作为主键

获取数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# -*- coding: utf-8 -*-

from django.http import HttpResponse

from app01.models import Test

# 数据库操作
def testdb(request):
# 初始化
response = ""
response1 = ""


# 通过objects这个模型管理器的all()获得所有数据行,相当于SQL中的SELECT * FROM
listTest = Test.objects.all()

# filter相当于SQL中的WHERE,可设置条件过滤结果
response2 = Test.objects.filter(id=1)

# 获取单个对象
response3 = Test.objects.get(id=1)

# 限制返回的数据 相当于 SQL 中的 OFFSET 0 LIMIT 2;
Test.objects.order_by('name')[0:2]

#数据排序
Test.objects.order_by("id")

# 上面的方法可以连锁使用
Test.objects.filter(name="runoob").order_by("id")

# 输出所有数据
for var in listTest:
response1 += var.name + " "
response = response1
return HttpResponse("<p>" + response + "</p>")

更新数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# -*- coding: utf-8 -*-

from django.http import HttpResponse

from app01.models import Test

# 数据库操作
def testdb(request):
# 修改其中一个id=1的name字段,再save,相当于SQL中的UPDATE
test1 = Test.objects.get(id=1)
test1.name = 'Google'
test1.save()

# 另外一种方式
#Test.objects.filter(id=1).update(name='Google')

# 修改所有的列
# Test.objects.all().update(name='Google')

return HttpResponse("<p>修改成功</p>")

删除数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# -*- coding: utf-8 -*-

from django.http import HttpResponse

from app01.models import Test

# 数据库操作
def testdb(request):
# 删除id=1的数据
test1 = Test.objects.get(id=1)
test1.delete()

# 另外一种方式
# Test.objects.filter(id=1).delete()

# 删除所有数据
# Test.objects.all().delete()

return HttpResponse("<p>删除成功</p>")