Django框架介绍
MVC、MTV模型介绍
MVC模型
将web应用分为模型M、视图V、控制器C三部分
模型:负责业务对象与数据库映射
视图:负责用户交互
控制器:接受用户的输入,调用模型和视图完成用户的请求
MTV模型
将web应用分为模型M、模板T、视图V三部分
模板:负责把页面展示给用户
除此之外,还有一个URL分发器,负载把一个个URL的页面请求分发给不同的View处理,View再调用相应的Model和Template
Django就是MTV模型
Django下载与创建新项目
Django下载
pip3 install django
创建一个Django项目
djang-admin.py startproject mysites
创建一个名为mysites的项目
创建一个Django应用
python manage.py startapp blog
创建一个名为blog的应用
注意:必须在项目下manage.py文件下面创建
启动Django项目
python manage.py runserver 8080
启动该项目,并且指定端口号8080
注意:不指定则默认127.0.0.1:8000
启动成功时,大致显示以下
Performing system checks...
System check identified no issues (0 silenced).
You have 14 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
August 12, 2018 - 15:26:57
Django version 2.0.1, using settings 'myproject1.settings'
Starting development server at http://127.0.0.1:8001/
Quit the server with CTRL-BREAK.
Django简单学习
Django目录分析
在项目目录mysites下有以下几个文件
settings.py: 配置文件,主要存储一些工作变量,数据库信息,调试标志
urls.py: url分发器,主要将传入的url映射到相应的视图函数
manage.py: Django项目里的工具,可以调用Django shell和数据库等
应用目录blog下文件分析
models: 主要用来存放调用数据库的程序
views: 主要用来存放视图函数
我们在urls中写url和相应的函数名,在views中实现该函数(注意返回render()对象),可以返回一个html页面。
在原目录下可以创建一个templates文件夹用来存放html文件。注意查看
找到setting-》找到TEMPLATES–》设置’DIRS’: [os.path.join(BASE_DIR, ‘templates’)]
render方法分析
该方法默认在views下面引入,自动读取HTML文件,返回bytes类型
render(request,"timer.html")
不需要写任何路径,django自动找templatas文件夹
如何将视图函数中的参数传入html中?
render(request,"timer.html",{"date":timer})
将参数字典传给html,在html中使用参数<h4>当前时间{{date}}</h4>
{{}}是一种反向解析的符号
HttpRespone方法分析
HttpRespone响应对象,只需要传入字符串,响应体;不需要传入响应头
在views下引入
from django.shortcuts import HttpResponse
示例:
def hi(request):
return HttpResponse("<h2>hi,you are bitch</h2>")
request类分析
我们每个视图函数都要有一个参数,即request;该类包含浏览器发过来的信息
在前端中form表单,method属性为提交方式,有GET和POST两种
方法名 | 功能 |
---|---|
request.method | 可以得到是"POST"还是“GET” |
request.GET | 得到一个GET请求字典 |
request.POST | 得到一个POST请求字典 |
示例:
如果我们想要从POST请求中得到表单中用户名(假设input标签name为user)
request.POST.get("user")
静态文件配置
在页面中,我们想引入jquery,css,js文件时,我们需要这么做
先创建一个静态文件夹static,然后找到settings.py加入以下代码
STATICFILES_DIRS=[
os.path.join(BASE_DIR,"statics")
]
我们通过浏览器可以直接访问到里面的内容,url为/static/*
例如:<script src="/static/jquery-3.3.1.js">
路由控制
哪个URL由哪个视图函数来处理,服务器接受到客户端发过来的请求时,在urls.py文件夹中这样处理。
url组成
协议://ip:端口号/路径?get请求数据
注意:没有路径时,默认根目录
re_path
在Django1.0版本中,re_path相当于url函数.放在在urlpatterns列表里
导入方法
from django.urls import re_path
示例一:
re_path(r'^articles/2003/$', views.special_case_2003)
前面是正则表达式,后面是匹配的视图函数
示例二:
re_path(r"^([0-9]{4})/([0-9]{2})/",views.mydate)
当我们使用分组匹配时,视图函数必须要有相应分组的取去接受参数
def mydate(request,year,month):
return HttpResponse("<h2>now time is</h2>"+year+"year,"+month+"month")
注意:
- 路径不要添加前导斜杠
^articles/2003/$
不要写为^/articles/2003/$
- 表达式前面最好加r,代表原始字符串,不用转义
- 如果路径满足好几个表达式,取最先满足的表达式
有名分组
示例三:
re_path("^(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/",views.mydate)
给每个分组起名字后,视图函数将按照关键字传参,而不是位置传参.这里形参数必须为year
,month
,但是位置可以改变
path
在Django2.0中,默认使用path来处理url映射,放在在urlpatterns列表里
注意:在re_path中匹配的参数默认是字符串
导入方法
from django.urls import path
示例一:
urls中path("<int:year>/<int:month>/",views.mytime,name="y_m")
这里使用<>尖括号,int代表匹配任意多个数字,并转换为Int格式,year,month代表将匹配到的内容赋值给这个变量
默认转换器
转换器 | 功能 |
---|---|
str | 匹配除路径分隔符以外的非空字符串,默认 |
int | 匹配正整数包括0 |
slug | 匹配字母,数字以及斜杠,下划线组成的字符串 |
uuid | 匹配格式化uuid |
path | 匹配任何非空字符串,包含路径分隔符 |
注意:没有转换器则匹配任何字符串,无需转换器前加前导斜杠
自定义转换器
当我们对匹配的内容有要求,且默认转换器不能满足我们的要求时,这时候我们就需要自定义转换器
首先定义一个类
包含一个regex类属性和to_python(self, value)
方法和to_url(self, value)
方法
to_python(self, value)
方法:类属性regex所匹配到的字符串,返回具体的Python变量值,以供Django传递到对应的视图函数中。
to_url(self, value)
方法:和to_python相反,value是一个具体的Python变量值,返回其字符串,通常用于url反向引用。
例如:
class MyMonth:
regex = "[0-9]{2}"
def to_python(self,value):
return int(value)
def to_url(self,value):
return '%04d' % value
将其注册到urls配置中
导入模块
from django.urls import register_converter
注册转换器
register_converter(MyMonth,"mm")
将该转换器其别名为mm
使用转换器
path("<mm:month>/",views.mymonth),
分发
当我们一个项目有多个应用时,url控制器不应该直接处理传过来的地址,而是将其分发给指定的应用,让应用内的url控制器进行映射操作
导入方法
from django.urls import include
示例四:
将url开头为blog/
的地址分发给blog
里的url控制器(blog
应用文件夹中必须创建一个urls.py文件)
re_path("^blog/",include("blog.urls"))
然后在blog的urls.py文件中添加相应的路由操作
from django.urls import re_path
from blog import views
urlpatterns = [
re_path("hi/",views.hi)
]
注意:当url地址为http://127.0.0.1:8000/blog/hi/
,项目url控制器得到的是blog/hi/
,匹配到blog/
后,将其分发给blog下的url控制器,该控制器得到的是hi/
,即匹配到视图
反向解析
当我们在模板(html网页)或者python代码中需要url链接地址时,我们需要反向解析得到链接的地址
在使用反向解析前,我们需要给url起一个别名,以便在修改控制器地址时,不影响已经使用该地址的地方。
给一条re_path起别名
re_path("^info/",views.info,name="info"),
使用reverse在python代码中反向解析
导入模块
from django.urls import reverse
示例一:
urls中:re_path("^info/",views.info,name="info")
views中:
from django.urls import reverse
print(reverse("info"))
解析出地址为/info/
只会解析出正则匹配的部分
比如地址后缀为/info/haha
,解析出来还是为/info/
示例二:
urls中:re_path("^([0-9]{4})/([0-9]{2})",views.mytime,name="y_m")
views中:
def mytime(request,year,month):
from django.urls import reverse
return HttpResponse(reverse("y_m",args=(year,month)))
注意:当正则表达式分组匹配带有参数时,需要传入符合规范的参数,args的元组中
使用{% %}在html中反向解析
示例二:
html中:
<p>当前匹配到的年{{ year }} 月{{ month }}</p>
<p>反向解析{% url "y_m" year month %}</p>
第一个标签是{{变量}}的方式反向解析到year,month两个变量
在views视图函数中由render(request,"mytime.html",{"year":year,"month":month})
这样传入的
第二个标签是{% “url的name” %},这个name是在url控制器中的一条re_path
re_path("^([0-9]{4})/([0-9]{2})",views.mytime,name="y_m")
名称空间
当我们使用include来分发url给不同应用时,我们可以设置一个名称空间,以便防止不同应用中名字重复
示例:
url中:re_path("^blog/",include("blog.urls",namespace="blog")),
views中:
urlpatterns = [
re_path("hi/",views.hi,name="hi"),
]
在python中
def hi(request):
return HttpResponse("<h2>hi,you are bitch,this is blog</h2>"+reverse("blog:hi"))
注意:
遇到这个错误时Specifying a namespace in include() without providing an app_name
在app_name
目录下的urls.py
文件中urlpatterns前面加上app_name='[app_name]'
,其中app_name
为项目名称。
例如:app_name = "[blog]"
视图层
也就是views.py文件,主要是用于编写视图函数
from django.shortcuts import render,HttpResponse,reverse
def index(request):
return render(request,"index.html")
index
就是视图函数
request属性和函数
属性 | 方法 |
---|---|
request.GET | 存储get字典 |
request.POST | 存储post字典 |
request.method | 表示请求使用的HTTP方法,是POST还是GET |
request.path | 表示请求的路径,不包括域名 |
访问网站:http://127.0.0.1:8080/abc?name=alex
函数 | 方法 |
---|---|
requset.path() | 请求路径(例如:返回/abc ) |
request.get_full_path() | 请求路径包括?后面的选项(例如:返回 /abc?name=alex ) |
响应对象分析
对象 | 属性 |
---|---|
HttpResponse() | 传入一个字符串,直接将字符串发给浏览器 |
render() | 解析模板,将网页发给浏览器 |
redirect() | 传递要重定向的一个硬编码的URL |
render()使用
将一个模板页面中的模板语法进行渲染,最终渲染成一个html页面作为响应体。
def index(request):
return render(request,"index.html")
传入request
对象,模板对象,可选参数字典
redirect()使用
传递要重定向的一个硬编码的URL
def my_view(request):
...
return redirect('http://example.com/')
默认返回临时重定向,参数permanent=True
返回永久重定向
状态码301和302有什么区别?
301表示旧网页资源已被永久移除,搜索引擎抓取将旧网址交换为重定向之后的网址
302表示临时从旧地址A跳到地址B,搜索引擎会保存旧网址
模板层
通常将HTML文件存在templates文件夹中
变量
{{var_name}}
将该语言写在HTML文件中,var_name
映射的是python变量。在视图函数返回的render()
中第三个参数传入的键值对,就是以python变量名为键,var_name
为值。
如果变量名过多可以不用一个一个组成字典传入render()
吗?
可以使用locals()
函数,将函数内所有变量传入,但是在HTML中使用的名称和python变量名一致
点语法
语法 | 功能 | 示例 |
---|---|---|
点+索引 | 获取列表中的元素 | l1.1 |
点+键 | 获取字典中的元素 | dic.name |
点+属性 | 获取对象属性 | date.year |
点+方法 | 获取对象方法(无参数) | dic.name.upper |
过滤器
{{obj|filter__name:param}}
可以将传入的变量使用函数过滤掉,该函数最多可以再传入一个参数param
过滤器 | 示例 | 功能 |
---|---|---|
default | {value|default:"没有值"} | 如果变量为空时,设置默认值 |
length | {l1|length} | 计算字符串或列表长度 |
data | {value|date:"Y-m-d"} | 格式化时间 |
slice | {value|slice:"1:-1"} | 列表切片操作 |
truncatechars | {value|truncatechars:9} | 截断字符串 |
safe | {value|safe} | 使变量中标签尖括号<> 不必转义为< 和> |
标签
第一种:{% tag %}
第二种{% tag %}
…{% endtag %}
for标签
使用for循环可以遍历变量
示例:
{% for key,val in dic.items %}
<p>{{ key }}:{{ val }}</p>
{% endfor %}
可以使用{% for obj in list reversed %}
反向完成循环
在for循环体中使用{% empty %}
可以将变量为空或没有值的变量设置默认值
{% for person in person_list %}
<p>{{ person.name }}</p>
{% empty %}
<p>sorry,no person here</p>
{% endfor %}
if标签
判断标签
示例:
{% if num > 100 or num < 0 %}
<p>无效</p>
{% elif num > 80 and num < 100 %}
<p>优秀</p>
{% else %}
<p>凑活吧</p>
{% endif %}
with标签
给变量起别名
示例:
{% with total=business.employees.count %}
{{ total }} employee{{ total|pluralize }}
{% endwith %}
别名只能在中间使用
csrf_token标签
用于跨站请求伪造保护,通常写在用于post提交的form表单中
{% csrf_token %}
自定义标签和过滤器
前提:
- 在setting.py文件下
INSTALLED_APPS = []
列表中添加应用名app - 该应用app下面有templates文件夹
- 在templates文件夹下创建一个后缀名为py的文件例如
my_tag_filter.py
文件中必须包含
from django import template
from django.utils.safestring import mark_safe
register = template.Library() #register的名字是固定的,不可改变
创建自定义过滤器
使用register.filter装饰器
@register.filter
def my_filter(x,y):
return x+y
注意:自定义过滤器最多只能有两个参数,第一个参数为|前的参数,第二个参数为:后面的参数
HTML中使用示例
from templates.my_tag_filter import *
{{ num|my_filter:3 }}
假设num为4,这{{ num|my_filter 3}}
结果为12
注意:使用自定义过滤器时,要导入相关文件
使用register.simple_tag装饰器
@simple_tag
def my_tag(x,y,z):
return x+y+z
注意:使用自定义标签时,可以传入一个或多个参数,不受限制
HTML使用示例
from templates.my_tag_filter import *
{% my_tag 5 6 7 %}
{% my_tag 5 6 7 %}
结果为18
自定义标签和自定义过滤器有什么不同???
- 自定义标签使用
{% tag %}
自定义过滤器使用{{ num|filter }}
或者{% if num|my_filter:3 > 4 %}
标签中 - 自定义标签可以设置多个参数,自定义过滤器只可以设置两个参数
- 自定义过滤器可以在if标签使用,自定义标签不行
示例:
{% if num|my_filter:3 > 4 %}
{{ num|my_filter:5 }}
{% endif %}
如何解决自定义过滤器只能传入两个参数的麻烦?
第二个参数使用列表。。。
模板继承
include关键字
{% include advertise.html %}
可以将外部html插入到该处,有助于代码复用
extends关键字
在基本版本HTML中使用block标签
home.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="http://code.jquery.com/jquery-latest.js"></script>
<link href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css" rel="stylesheet">
<title>{% block title %}这是基本模板{% endblock %}</title>
</head>
<body>
<div class="container">
<div class="row">
<ul class="nav nav-pills">
<li role="presentation" class="active"><a href="#">Home</a></li>
<li role="presentation"><a href="#">杂</a></li>
<li role="presentation"><a href="#">关于</a></li>
</ul>
</div>
<div class="row">
{% block content %}
<h1>空</h1>
{% endblock %}
</div>
</div>
</body>
</html>
block
标签的作用相当于一个占位符,后面html页面导入该页面时要替换他
在版本中,只要导入该基本版,然后填充block
标签里的内容就可以使用
{% extends "base.html" %}
{% block title %}
主页
{% endblock %}
{% block content %}
<p>这里是主页</p>
{% endblock %}
extends
标签的作用是将html模板导入该页面
注意:
- 在基本版HTML页面中,
{% block %}
标签包裹的内容是默认内容,就是没有设置该标签时,显示的内容 - 如果页面想要在原来默认内容上拓展内容,就在子HTML的
block
标签中添加{{ block.super }}
示例:
{% block con%}
{{ block.super }}
在原继承基础上,需要拓展的内容
{% endblock %}
- 可以在endblock后面添加一个名字
{% block con %}
{% endblock con %}