简介

Django一个由python编写的基于MVC框架模式的开源web框架,具有… …

MVC和MTV

MVC即Model+View+Controller是一种常见的web框架模式,但很难将Django严谨的分为于是有了Django特有的MTV框架模式即Model+Template+View

  • Model即模型,主要负责数据库和视图之间的沟通
  • View即视图,主要负责网页中的业务逻辑,调用Model数据传递给Template
  • Template即模板,主要负责渲染页面展示给用户

Django项目和基础设置

创建Django项目

使用django-admin startproject demo1 在当前目录创建一个名为demo1的django项目 ### 创建APP应用 使用python manage.py startapp app1 在当前django项目中创建一个名为app1的APP应用 在setting.py的INSTALLED_APPS中增加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',
'app1',
]

项目结构

  • setting.py:整个django项目中的配置文件
  • url.py:url配置文件,用于将url与视图联系起来
  • wsgi.py:网关接口,用于沟通联系django和虚拟主机中的web服务器
  • migrations:用于存放Model生成的数据库迁移文件
  • admin.py:django自带管理界面的管理文件
  • models.py:Model文件,在里面定义需要使用的数据库模型类
  • view.py:视图文件,用于编写各个视图

设置语言与时区

在setting.py文件中

1
2
3
LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/ShangHai'
zh-hans:使用汉语 Asia/ShangHai:使用亚州上海时区

启动django项目

使用python manage.py runserver启动django

URL设置

在url.py文件中urlpatterns列表中添加path或者re_path来绑定url和视图函数

1
2
3
4
5
6
7
8
9
10
from django.contrib import admin
from django.urls import path,include
from . import views

urlpatterns = [
path('admin/', admin.site.urls),
path('', views.index),
path('book/',include("B.urls")),
re_path(r'^abc$',view.abc)
]

路由绑定

  • path:用来绑定字符串路由和视图函数,第一个参数为路由,第二个参数为绑定的视图函数
  • re_path:用来绑定re正则路由和视图函数,第一个为匹配路由的正则表达式,第二个参数为绑定的视图函数
  • include:指定子路由文件 (path(‘book/’,include(“B.urls”))即将book/路由下的所有子路由配置放到B文件夹下的urls.py文件)

路由参数

1
path('/<int:id>',view.index)

匹配任意int类型url,并且该路由参数可被视图函数接收参数名为id 其余类型参数:

str 字符串类型
int 整数类型
slug ASCII编码
uuid uuid格式
path URL路径类型

路由命名

为了方便在模板中调用路由通常会给路由进行命名,在模板只需要调用名称即可获得相应路由

1
2
3
4
path('/<int:id>',include(("B.urls","index")),namespace="user")
# namespace是对该路由进行命名,使用namespace时第一个参数必须为元组,第二个元素自行命名,一般为项目名称
path('/<int:id>',view.index,name='index') # name参数为对该路由定义名称
path('/<int:id>/<str:name>',view.index,name='login') # name参数为对该路由定义名称

namespace是对指定子路由整个进行名称定义,一般配合name使用

在templates模板中调用方法

1
2
3
4
<a href="{% url 'index' %}"> 只使用name时</a>
<a href="{% url 'user:index' %}">使用namespace和name时</a>
<a href="{% url 'user:index' '10' %}">当Url有变量时需要将变量给出,如上示例</a>
<a href="{% url 'user:login' '10' 'name' %}">当Url有变量时需要将变量给出,如上示例</a>

反向解析

可以通过url反向解析出该url的name和namepace等信息

1
2
3
4
5
6
7
from django.shortcuts import reverse
from django.urls import resolve
args = ['10']
reverse("user:index",args=args)
# 通过reverse可以生成路由地址
resolve(reverse('/10/name'))
# 通过resolve将路由地址转变成对象

resolve的内置函数

函数名称 功能
func 路由的视图函数对象或视图类对象
args 以列表格式获取路由的变量信息
kwargs 以字典格式获取路由的变量信息
url_name 获取路由命名name
app_name 获取include函数第二个元素值
app_names 同上,以列表格式表示
namespace 获取路由的命名空间
namespaces 同上,以列表格式表示
view_name 获取整个路由的名称,包括命名空间

路由重定向

通过urls.py文件配置路由重定向

1
2
3
4
5
6
7
from django.contrib import admin
from . import views
from django.views.generic import RedirectView
urlpatterns = [
path('', views.index),
path('tz', RedirectView.as_view(url='/'),name='tz')
]

通过视图函数进行重定向

1
2
3
4
5
from django.shortcuts import redirect
def index(request):
return redirect('/',permanent=true)

# permanent为true为永久跳转,flase为临时跳转

Views

view负责主要的业务逻辑,并从数据库查询数据同时反馈给template

基本视图函数

1
2
3
4
from django.http import HttpResponse 
def index(request):
return HttpResponse('Hello World')
#HttpResponse将字符串Hello World传给浏览器
相应类型 说明
HttpResponseRedirect(“/”) 状态码302,重定向到该地址
HttpResponsePermanentRedirect(“/”) 状态码301,永久重定向到该地址
HttpResponseBadRequest(“400”) 状态码400,访问页面不从在或请求错误
HttpResponseNotFound(“404”) 状态码404,访问的页面不存在或请求错误
HttpResponseForbidden(“403”) 状态码403,没有访问权限
HttpResponseNotAllowed(“405”) 状态码405,不允许使用该请求方式
HttpResponseServerError(“500”) 状态码500,服务器内容错误
JsonResponse(“{‘key’:‘value’}”) 状态码200,响应json数据
StreamingHttpResponse() 状态码200,以流式输出

使用HTML文件

1
2
3
4
5
from django.shortcuts import render,redirect
def index(request, id):
data = {'id':id}
return render(request,'index.html',data,status=200)
#id为接收的url参数,index.html为使用的HTML文件,data为传到模板的数据,data为字典,status为状态码

绑定404与500页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#view函数
from django.shortcuts import render
def page_not_found(request, exeption):
return render(request, '404.html', status=404)
def page_error(request):
return render(request, '500.html', status=500)
#url绑定
from django.urls import path
from . import view

urlpatterns = [
path('', view.index),
]
handler404 = view.page_not_found
handler500 = view.page_error

下载视图

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
37
38
39
40
41
42
43
44
45
46
#urls.py文件
from django.contrib import admin
from django.urls import path
from . import view

urlpatterns = [
path('', view.index),
path("download/1", view.download1, name='download1'),
path("download/2", view.download2, name='download2'),
path("download/3", view.download3, name='download3'),
]
#views.py文件
from django.shortcuts import render

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

def download1(requests):
name = '/home/way/Window10/wallppaper/anime-1542227-wallhere.com.png'
try:
r = HttpResponse(open(name, 'rb'))
r['content_type'] = 'application/octet-stream'
r['Content-Disposition'] = 'attachment;filename=bj1.png'
return r
except:
raise Http404("Download error")


def download2(request):
name = '/home/way/Window10/wallppaper/anime-1562445-wallhere.com.jpg'
try:
r = StreamingHttpResponse(open(name, 'rb'))
r['content_type'] = 'application/octet-stream'
r['Content-Disposition'] = 'attachment;filename=bj2.png'
return r
except:
raise Http404("Download error")


def download3(request):
name = '/home/way/Window10/wallppaper/anime-1562445-wallhere.com.jpg'
try:
r = FileResponse(open(name,'rb'), as_attachment=True, filename='bj3.jpg')
return r
except:
raise Http404("Download error")

上传视图

1
2
3
4
5
6
7
8
9
10
11
12
13
def upload(request):
myfile = request.FILES.get("myfile")
f = open("name","rb")
for chunk in myfile.chunks():
f.write(chunk)
f.close()
#模板文件
<form enctype="multipart/form-data" action="" method="POST">
{% csrf_token %}
<input type="file" name="myfile"/>
<br>
<input type="submit" value="上传文件"/>
</form>

Templates

设置使用

  1. 在项目目录下templates文件夹

  2. 在setting.py文件中配置templates文件夹路径

    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')], #将此处改为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. 增加static文件夹路径

    1
    STATICFILES_DIRS = [os.path.join(BASE_DIR,'static'),]        #在setting.py中新增此项
    ### template语法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    {{ name }}                  #加载视图函数传出的字典中'name'字段数据、

    {% load static %} #加载static文件,在整个html文件中使用一次即可

    {% static "文件路径" %} #设置static文件路径

    {% if 条件 %}内容{% elif 条件 %}内容{% endif %} #if条件判断,可以使用or,and,not,in

    {% for i in value %}内容{% empty %}内容{%cycle 'a' 'b'%}{% endfor %} #条件循环判断,当value没有值时输出empty内容,cycle中第一次循环输出a第二次输出b第三次输出a

    {% url xxx:xxx %} #通过路由名称获取Url
    {% extends xxx %} #继承xxx模板
    {% block xxx %} #将该代码定义为父代码供extends继承

    for 标签变量

forloop.counter 循环当前迭代(从1开始索引)
forloop.counter0 循环当前迭代(从0开始索引)
forloop.revcounter 循环当前迭代(倒叙)
forloop.revcounter0 循环当前迭代(倒叙从0开始索引)
forloop.first 当第一次循环时为真
forloop.last 最后一次循环时为真
forloop.parentloop 当嵌套循环时,parentloop表示外层循环

自定义标签

  1. 在项目目录下创建标签文件夹并在该目录下创建templatetags文件夹

  2. 将标签文件夹名称注册进app配置里(和app注册一样)

  3. 在templatetags目录下创建mytags.py文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    from django import template

    # 创建模板对象
    register = template.Library()


    # 定义模板节点类
    class ReversalNode(template.Node):
    def __init__(self, value):
    self.value = str(value)

    def render(self, context):
    return self.value[::-1]


    # 注册标签名,如果没设标签名则用函数名
    @register.tag(name='mytage')
    def do_reversal(parse, token):
    try:
    tag_name, value = token.split_contents()
    except:
    raise template.TemplateSyntaxError("syntax")
    return ReversalNode(value)
  4. 在html文件中使用自定义标签需要先使用{% load mytags %}吧自定义标签加载进去,mytags为创建的文件名

过滤器

用法

1
{{变量|过滤器:值|过滤器:值}}
| add | 为value的值增加 | | — | — | | addslashes | 为字符串需要的地方加上转移字符 | | capfirst | 为字符串加上首字母大写 | | center、ljust、rjust | 为字符串内容设置居中、靠左、靠右 | | cut | 在字符串中删除指定的子字符串 | | date | 设置日期的显示格式 | | default | 如果没有值,就使用默认值 | | dictsort | 为字典形式内容的变量排列顺序 | | dictsortreversed | 上一指令的反向排序 | | divisibleby | 测试数值数据是否可被指定的数整除 | | escape | 把字符串中的HTML标签变成显示用的字符串 |

filesizeformat 以人们习惯的方式显示文件大小格式
first 只取出列表数据中的第一个
last 只取出列表数据中的最后一个
length 返回列表数据的长度
length_is 测试数据是否为指定长度
floatformat 以指定的浮点数格式来显示数据
linebreaks 把文字内容的换行符号转换为HTML的
linebreaksbr 把文字内容的换行符转换成
linenumber 为显示的文字加上行号
lower/upper 把字符串内容全部换成小写/大写
random 以随机数将面前的数据内容显示出来
safe 把字符串为安全的,不需要再处理转移字符
slugify 标记字符串空格变成“-”,让此字符串可以放在网址栏
striptags 把所有HTML标记都删除
truncatechars 把过长的字符串裁切成指定长度
wordcount 计算字数
yesno 按照只的内容时True、False还是None,显示出有意义的内容

自定义过滤器

  1. 创建方式同自定义标签

  2. ```python from django import template

    register = template.Library()

    @register.filters(name=‘replace’) def do_replace(value, agrs): oldValue = agrs.split(“:”)[0] newValue = agrs.split(‘:’)[1] return value.replace(oldValue, newValue)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

    ### 使用Jinja2模板引擎

    Jinja2模板引擎设计思想源于Django模板引擎,并拓展了其语法与功能,是Python里面被广泛应用的模板引擎

    1. 使用pip安装Jinja2库

    2. 在setting同级目录创建jinja2.py文件

    ```python
    from django.contrib.staticfiles.storage import staticfiles_storage
    from django.urls import reverse
    from jinja2 import Environment

    def environment(**options):
    env = Environment(**options)
    env.globals.update({
    'static': staticfiles_storage.url,
    'url': reverse,
    })
    return env
  3. 将jinja2.py文件中的函数写入setting.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    TEMPLATES = [
    {
    'BACKEND': 'django.template.backends.jinja2.Jinja2',
    'DIRS': [BASE_DIR / 'djangoProject/jinja2.py',BASE_DIR / 'templates'], #需要将jinja2配置文件和templates文件夹都写进来
    'APP_DIRS': True,
    'OPTIONS': {
    'environment': 'djangoProject.jinja2.environment'
    }
    },
    {
    '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',
    ],
    },
    },
    ]

Jinja2 for循环标签变量

变量 描述
loop.index 循环的当前迭代,索引从1开始
loop.index0 循环的当前迭代,索引从0开始
loop.revindex 循环结束时的迭代次数,索引从0开始
loop.revindex0 循环结束时的迭代次数,索引从1开始
loop.first 如果是第一次迭代就为True
loop.last 如果是最后一次迭代久违True
loop.length 循环总次数
loop.depth 当前循环深度,从1级开始
loop.depth0 当前循环深度,从0级开始
loop.previtem 上一次迭代对象
loop.nextitem 下一次迭代对象
loop.changed(value) 若是上次迭代的值与当前迭代的值不同,则返回True

jinja2常用过滤器

过滤器 说明
{{value\|abs}} 设置数值的绝对值
{{ value\|default('new')}} 设置默认值
{{ value\|escape}} 转义字符,转成HTML语法
{{ value\|first}} 获取第一个元素
{{ value\|last}} 获取最后一个元素
{{ value\|length}} 获取长度
{{ value\|join('-')}} 同python用法
{{ value\|safe}} 转义处理
{{ value\|int}} 转成Int型
{{ value\|float}} 转成float型
{{ value\|lower}} 转成小写
{{ value\|upper}} 转成大写
{{ value\|replace('a','b')}} 字符串替换
{{ value\|truncate(9,true)}} 字符串截断
{{ value\|striptags}} 删除value中所有的HTML标签
{{ value\|trim}} 删除value前后的空白字符
{{ value\|string}} 转换成字符串
{{ value\|wordcount}} 计算字符串的单词个数

自定义JInja2的过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#修改jinja2.py文件

from django.contrib.staticfiles.storage import staticfiles_storage
from django.urls import reverse
from jinja2 import Environment

# 过滤器处理函数
def myReplace(value, old='JInja2', new='Django'):
return str(value).replace(old, new)


def environment(**options):
env = Environment(**options)
env.globals.update({
'static': staticfiles_storage.url,
'url': reverse,
})
# 注册函数
env.filters['myReplace'] = myReplace
return env

Models

主要负责数据库和视图之间的沟通数据库是动态网站的重要组成部分,在Django中使用了ORM的概念把数据存取的过程进行了抽象化,通过Models来定义数据表。 ### 数据库配置 Django默认使用的是自带的一个小型数据库,只支持测试使用,所以使用时必须现在setting文件中进行相应的数据库配置,以下为MySQL配置。

1
2
3
4
5
6
7
8
9
10
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', #使用MySQL作为数据库
'NAME': 'mydb', #数据库名称
'USER': 'root', #数据库用户名
'PASSWORD': '123456', #数据库密码
'HOST': '10.30.59.136', #数据库IP
'PORT': '3306', #数据库端口
}
}
打开项目同名目录下的_int_.py文件,在里面写入以下代码
1
2
3
4
import pymysql
pymysql.install_as_MySQLdb() #MySQLdb并不支持python3.x 需要使用pymysql并设置为和MySQLdb同样使用

#需要安装pymysql库
### 创建数据表

  • 在APP目录里models.py文件里创建数据表模型
    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
    class Model(models.Model):                               
    字段名=models.字段类型()


    class Demo(models.Model):
    boolean = models.BooleanField(max_length=10) #布尔类型
    char = models.CharField() #varchar类型
    date = models.DateField() #date类型
    datetime = models.DateTimeField() #datetime类型
    double = models.FloatField() #double类型
    decimal = models.DecimalField() #decimal类型
    email = models.EmailField() #存储邮箱varcgar类型存储
    int = models.IntegerField() #int类型
    image = models.ImageField() #保存图片路径
    text = models.TextField() #logtext类型

    # max_length 设置长度
    # primary_key 设置主键
    # blank 是否允许为空
    # null 允许为空
    # default 默认值
    # db_index 是否增加索引
    # unique 是否为唯一值
    # db_column 指定字段名
    # verbose_name 后台显示名称


    #设置外键
    book = models.ForeignKey(Demo2,on_delete=models.CASCADE)
    # Demo2 为外键指向的另一张表的类名
    ### 数据库迁移 该步目的为把models里的数据表模型在数据库中创建或更新

生成迁移文件 python manage.py makemigrations 执行迁移文件生成表 python manage.py migrate ### 数据库操作

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
37
38
39
40
41
#数据库操作格式
类.object.操作方法

#增加数据
Demo.object.create(字段=数据)

#查询数据
Demo.object.all() #查询该表全部数据
Demo.object.values("字段") #查询指定字段
Demo.object.filter(字段=参数,字段=参数) #条件查询(多参数时为与)
Demo.object.exclude(条件) #返回不包含此条件的数据
Demo.object.get(条件) #只获取一条数据,如果查询结果多于一条时报错

#排序
Demo.object.order_by("字段") #根据字段排序

#更新数据
filter = Demo.object.filter(字段=参数,字段=参数)
filter.name = "name" #将查询结果中的name字段内容更新成"name"
filter.save()
#该方法指定修改一条数据
filter = Demo.object.filter(字段=参数,字段=参数).update(name = "name")
#批量修改多字段

#删除数据
Demo.object.all().delete() #批量删除全部数据
Demo.object.filter(字段=参数,字段=参数).delete() #批量删除符合条件的数据
Demo.object.get(条件).delete() #删除一条数据
查询谓词
用法在操作方法里面跟在字段后
Demo.object.filter(id__exact=1)
#__exact 等值查询
#__contains 包含指定值
#__startswith 以xxx开始
#__endswith 以xxx结束
#__gte 大于等于指定值
#__lt 小于指定值
#__lte 小于等于指定值
#__gt 大于指定值
#__in 查找数据是否在指定范围(in)
#__range 查找数据是否在指定的区间范围(between)
### 将数据表添加到admin页面管理

  1. 在APP目录下的admin.py文件中以以下格式注册数据表

    1
    admin.site.register(models.Demo)         #Demo为数据表类名

  2. 使用命令行在项目目录下使用命令创建超级用户

    1
    python manage.py createsuperuser

  3. 打开//admin/页面登陆超级账号

在后台显示的数据表字段名可以在models.py中使用verbose_name设置

  1. admin设置
    1
    2
    3
    4
    5
    6
    class BookManage(admin.ModelAdmin):
    list_display=['name','author','date'] # admin中显示字段
    list_display_links=['author'] #控制可以进入更改页面的字段
    list_filter=['author'] #增加过滤器(分类)
    search_fields=['name','author'] #开启搜索框,可以根据指定字段搜索
    list_editable=['name'] #设置允许在更改列表页面改动的字段
    ### Models内部类
    1
    2
    3
    4
    5
    模型类内部类 Meta
    class Meta:
    db_table = '数据表名' 设置数据表名称
    verbose_name = '单数名' 给模型对象一个名称,用于在admin管理界面中显示
    verbose_name_plural = '复数名' 给模型对象一个名称,用于在admin管理界面中显示
    ### F()和Q() F()可以用来对数据中字段值进行引用
    1
    2
    3
    filter = Demo.object.filter(字段=参数,字段=参数).update(age = F("age")+10)
    #获取该查询中的age字段并在原本的age字段数值+10重新赋值给age
    #可以防止多用户同时访问时数据更新不及时造成数据存储错误
    Q()用来复杂条件查询
    1
    2
    3
    4
    5
    filter = Demo.object.filter(Q(name="python")|Q(name="java"))
    Q()支持使用逻辑运算符
    Q('字段')|Q('字段') 逻辑或
    Q('字段')&Q('字段') 逻辑与
    Q('字段')~Q('字段') 逻辑非
    ## Cookice和Session