参考地址:http://www.cnblogs.com/yuanchenqi/articles/7629939.html
一、什么是Django
Django是一个Web应用程序的框架。
预备知识:1、python基础 2、数据库 3、前端( jquey + bootstrap )
1.1、Django请求生命周期
二、Web请求的本质
CS架构:client --- server #客户端 -- 服务端
BS架构:browser --- server #浏览器 -- 服务端
三、MTV模型
M 代表模型(Model): 负责业务对象和数据库的关系映射(ORM)。与数据库交互
T 代表模板(Template): 负责如何把页面(根据请求,决定给用户什么样的页面)展示给用户(HTML)。
V 代表视图(View): 负责业务逻辑,并在适当的时候调用Model和Template(把数据封装成模板的样子返还给用户)。
图解MTV模型:
URL控制器:什么路径 ( login | admin | index 等) 交给什么函数去处理。
四、Django学习过程
4.1、下载与命令 -- 在命令行操作的方式 ( django是依赖于Python库的,用什么pip版本下载的,django就存在于对应版本的Python库的Scripts目内[django-admin.exe] )
下载: pip3 install django==1.11.1 #最新版本django-2.1.4
卸载: pip3 uninstall django-1.11.1
创建项目:django-admin startproject mysite #其中mysite为项目名称(项目名可以修改)
创建一个应用:python3 manage.py startapp app01 #app01为应用名称
项目启动命令:python3 manage.py runserver IP+PORT #默认是127.0.0.1:8000
mysite 项目包含的:
1 --- mysite #和项目名称同名的目录(不能更改名称)
--- settings 项目配置文件
--- urls 路径与视图函数的映射关系
--- wsgi 封装的socket
2 --- manage.py Django项目进行交互的脚本
3 --- app01 项目应用 #python3 manage.py startapp app01(创建一个应用)
--- models 数据库操作
--- views 视图函数
4 --- app02 项目应用 #python3 manage.py startapp app02(创建一个应用)
--- models 数据库操作
--- views 视图函数
5 --- templates #存放模板的文件夹(名称必须为templates)
--- index.html
--- login.html
4.3、查看django版本号 pip show django
4.4、在pycharm中创建Django项目的方式
方式一:使用现有的Python(版本)环境
方式二:创建一个新的Python虚拟环境
make available to all projects:表示创建的项目工程可以被其他项目使用
inherit global site-packages:继承本地的Python版本库
五.URL控制器 urls.py -- Django实践
URL: 协议://IP(域名):端口(80)/路径?GET参数
URL的功能:反映URL的路径和视图函数的映射关系
5.1、URL的简单使用 -- 在urls.py文件配置
from app01 import views # 指定路径
urlpatterns = [
url(r'^timer/', views.timer), #views.timer(request) django会帮我们把http请求头的信息拿到,默认传进去。
]
然后在应用目录APP01的views.py文件里,定义timer
from django.shortcuts import render,HttpResponse
# HttpResponse为封装响应体的类
def timer(request): # request请求信息对象
import time
ctime=str(time.time())
return HttpResponse(ctime) # 执行timer函数,[HttpResponse这个类在实例化的时候需要传入的值为字符串类型,所以ctime要设置为字符串类型]
访问:http://127.0.0.1:8000/timer/ 拿到当前机器的时间!
5.2、URL的无名分组 -- 一般用来传URL路径里面的某一个参数,或者说是获取URL路径里面的某一个参数。
# 在urils.py里对应的配置。
from app01 import views
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^articles/(\d{4})/$', views.article_year),
]
# \d{4}:表示4位数字
# (\d{4}) :表示接收浏览器URL路径里面的某一个值,接收到的值会传给views.article_year(request,(\d{4})),那么在后端的代码里面article_year函数里面也要传2个参数。
# 在views.py里对应的配置。
def article_year(request,year):
#数据库查询
return HttpResponse(year)
5.2、URL的有名分组 -- 根据定义的关键字传参 -- 相当于关键字传参 -- (?P
# 在urils.py里对应的配置。
from app01 import views
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^articles/(?P\d{4})/(?P\d{2})/$', views.article_year_month),
# year接收传入的第一个值并赋值给year(year=1999),month接收传入的第二个值并赋值给month(month=12)
]
# 在views.py里对应的配置。
def article_year_month(request,year,month):
#数据库查询
return HttpResponse(year+"/"+month)
5.3、URL的分发 -- 每个应用下单独定义urls,只需要在项目目下做总的分发,实现解耦效果。
# 在项目目录下的urls.py文件内定义
from django.conf.urls import include, url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^app01/',include('app01.urls')) # 定义访问app01应用的走app01目录下urls.py文件
]
# 那么在app01目录下urls.py文件定义如下:实现解耦的效果
from django.conf.urls import include, url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
# 无名分组
url(r'^articles/(\d{4})/(\d{2})/$', views.article_year_month),
# 有名分组
url(r'^articles/(?P\d{4})/(?P\d{2})/$', views.article_year_month),
]
# 在views.py文件中的代码如下:
from django.shortcuts import render,HttpResponse
def article_year_month(request,year,month):
return HttpResponse(year+":"+month)
# 访问的URL就必须加上app01前缀,否则无法访问
# http://127.0.0.1:8000/app01/articles/2005/19/
5.4、URL的反射 -- 给固定的URL路径起一个别名,那么在使用路径时用这个别名即可。无论这个URL的路径在urls.py中如何修改,只要在前端html中定义"action={% url 'login' %}",那么"{% url 'login' %}"就总能获取到urls.py中定义的URL路径(前端HTML不需要修改对应的路径)。--可参照 (7.2、渲染URL标签 {% %} )
在Html中写法:
# 在html中,首先会查找有没有模板语法,如果没有的话,那么就直接丢给浏览器去读取html的内容了。
# 如果有模板语法,那么根据模板语法的内容,去全局的urls.py文件中找一个叫"login"的别名字符串。
# 找到"login"这个别名字符串后,会把这个别名对应的URL动态的获取,然后放在html中的action里面,然后交给浏览器去读取html中的action的内容。
]
例子:实现用户的登录及认证功能
# 前端HTML:
# 后端代码:
# 一、urls.py文件内
from app01 import views
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^timer/', views.timer),
# 二合一版本
url(r'^login/', views.login),
]
# 二、views.py文件内
from django.shortcuts import render,HttpResponse
def login(request):
method=request.method # request.method 拿到的是用户请求一个页面的方式"GET"或者"POST"
if method == "GET": # 判断用户的请求方式
return render(request,"login.html") # 如果为"GET",则返回"login.html"
else:
user=request.POST.get("user") # 通过“request.POST.get”,拿到前端用户输入的"用户名"
pwd=request.POST.get("pwd") # 通过“request.POST.get”,拿到前端用户输入的"密码"
# 校验数据
if user == "szq" and pwd == '123':
return HttpResponse('登录成功')
# 响应
return HttpResponse("登录失败")
六.视图语法 views.py
6.1、request -- 请求信息
# 在views.py文件里面编辑:
# 然后访问:http://127.0.0.1:8000/index/ 拿到如下信息!
def index(request):
# 请求信息
print(request.GET) # 发送GET请求
#
print(request.POST) # 发送POST请求
# < QueryDict: {} >
print(request.method) # 获取本次请求的方式 "GET或POST"
# GET
print(request.path) # 获取本次请求的相对路径
# /index/
print(request.get_full_path()) # 获取本次请求的全部路径(ip+port之后的路径地址)
# /index/?a=1
6.2、HttpResponse -- 响应信息
1、Django必须响应HttpResponse对象
2、HttpResponse 响应字符串
# 使用例子,在views.py文件中:
def index(request):
return HttpResponse("首页!")
3、render 响应模板(对应的html文件)
4、redirect 重定向 -- 用户登录成功后,重定向到网站首页! (服务器让浏览器重定向请求,浏览器相当于请求了2次服务器)
# 使用例子,在views.py文件中:
def login(request):
if request.method=="GET":
return render(request,'login.html')
else:
if 1:
return redirect("/index/") # 在这里做了重定向跳转,跳转的路径为"/index/",触发这次重定向之后,就会跳转到http://127.0.0.1:8000/index/这个页面。
七.模板语法 templates -- 模板语法都是由render解析的
7.1、render方法的功能:
方式一:return render(request,"login.html")
按着settings指定路径找到对应的login.html,读取文件内容,构建return HttpResponse(文件字符串)
方式二:return render(request,"timer.html",{"ctime":ctime, "name":name, "age":age,})
按着settings指定路径找到对应的timer.html,读取文件内容,进行渲染,把文件字符串中所有的{{}}的内容按着{"ctime":ctime, "name":name, "age":age,}的方式进行替换,将新的替换字符串构建return HttpResponse(文件字符串)
7.2、模板语法分为:
1.变量 :1)深度查询,2)过滤器
2.标签
1、模板语法之变量的用法 {{ }} 小例子:
# 渲染变量的
在Html中写法:
2、模板语法之标签{% %}的用法 小例子:渲染URL标签 -- 在Html模板里面对URL进行渲染 {% %}
# 渲染URL标签的
在Html中写法:
# 在html中,首先会查找有没有模板语法,如果没有的话,那么就直接丢给浏览器去读取html的内容了。
# 如果有模板语法,那么根据模板语法的内容,去全局的urls.py文件中找一个叫"login"的别名字符串。
# 找到后会把这个别名动态的获取,然后放在html中,然后交给浏览器去读取html的内容。
]
7.3、模板语法(变量)的使用:深度查询
在python中的用法:
如下:定义了"name" "l" "dic"等变量,以及类"Animal"等。
def template(request):
'''
模板语法:
变量
--- 深度查询
--- 过滤器
'''
name="sudada"
l=[11,22,33]
dic={"name":"sudada","age":18,"sex":"male"}
class Animal(object):
def __init__(self,name,age):
self.name=name
self.age=age
zzz=Animal("zzz",10)
lll=Animal("lll",20)
sss=Animal("sss",30)
person_list=[zzz,lll,sss]
return render(request,"templates.html",{"name":name,"l":l,"dic":dic,"person_list":person_list})
# return render(request,"templates.html",locals())
那么在前端是如何调用的呢? 前端HTML代码使用是效果展示:{{ }} 的方式调用Python里面定义的变量:
{{ name }}
# sudada 拿到变量name的赋值
<<---------分隔----------->>
{{ l }}
#[11, 22, 33] 拿到l列表里面定义的所有值
{{ l.0 }}
#11 取l列表里面定义的第一个值
{{ l.1 }}
#22 取l列表里面定义的第二个值
{{ l.2 }}
#33 取l列表里面定义的第三个值
<<---------分隔----------->>
{{ dic.name }}
#sudada 取字典里面的第一个值
{{ dic.age }}
#18 取字典里面的第二个值
{{ dic.sex }}
#male 取字典里面的第三个值
<<---------分隔----------->>
{{ person_list.0 }}
#.Animal object at 0x000001AFD0655198> 拿到的是实例化的对象,可以看出定义的类为"Animal"
{{ person_list.0.name }}
#zzz 拿到的是列表person_list里面实例化后的对象name对应的值,0表示列表里面的第一个对象,name表示对象name对应的值。
{{ person_list.0.age }}
#10 同上
{{ person_list.1.name }}
#lll同上
{{ person_list.1.age }}
#20同上
{{ zzz.name }}
# zzz 直接获取对象zzz的name对应的值
{{ zzz.age }}
# 10 直接获取对象zzz的age对应的值
7.4、模板语法(变量)的使用:过滤器语法 {{val(变量)|filter_name(过滤器名字):参数}} -- 更友好的显示一些数据
在python中的用法:
def template(request):
"""
过滤器的使用之语法:{{val(变量)|filter_name(过滤器名字):参数}}
"""
number=100
import datetime
now=datetime.datetime.now()
# book_list=["三国演义","金瓶梅"]
book_list=[]
file_size=12312311
s="Hello World"
article="asd,哈哈哈,asd,爱 asd asd 12 lasdj lqniuqg id bsmnc buqho namv uqbwi namsb iuqoiejlqkwbdbnmasb j"
link="rick"
# return render(request,"templates.html",{"name":name,"l":l,"dic":dic,"person_list":person_list}) # 写法一
return render(request,"templates.html",locals()) # 写法二
# locals() == {"name":name,"l":l,"dic":dic,"person_list":person_list}
那么在前端是如何调用的呢?
前端HTML代码使用是效果展示:
过滤器
{{number|add:20}}
# number变量名,"|"固定写法,add表示加法,":"固定写法,20表示数字。表示在number=100的基础上在加20
{{ now|date:"Y-m-d h:i" }}
# 原本"Dec. 30, 2018, 11:54 p.m."的格式加上过滤器date:"Y-m-d h:i"后,变成了"2018-12-30 11:54"
{{ book_list|default:"没有符合条件的数据" }}
# 当book_list=[]为空的时候,默认显示"没有符合条件的数据",当book_list=["三国演义","金瓶梅"]里面存在值的时候,就显示列表里面的值。
{{ file_size|filesizeformat }}
# 把file_size=123123123换算成字节大小,显示的效果为"117.4 MB"(格式单位自动调节),可以一眼看出文件有多大。
{{ s|slice:"0:3" }}
# 对s="Hello World" 切片(顾头不顾尾),取"0:3"的值
{{ s|slice:"0::2" }}
# 对s="Hello World" 切片(顾头不顾尾),每隔2个单位取一个值
{#展示一篇文章前面的一部分内容#}
{{ article|truncatechars:10 }}
# 展示一片文章的前7个字符(后面会默认加...三个字符)
{{ article|truncatewords:3 }}
# 展示一片文章的前3个单词(默认以空格为单词之间的分隔符分隔符)
{{ link|safe }}
# Django的安全机制会将link="rick"标签字符串进行转译,那么需要加上一个safe的过滤器,让他保持原意
7.4、自定义标签和过滤器
1、在settings中的INSTALLED_APPS配置当前app01(项目名),不然django无法找到自定义的simple_tag.
2、在app01中创建templatetags模块 (模块名只能是templatetags)
3、创建任意 .py 文件,如:my_tags.py,并自定义过滤器函数和标签函数
from django import template
from django.utils.safestring import mark_safe
register = template.Library() #register的名字是固定的,不可改变
@register.filter
def filter_multi(v1,v2): # 自定义过滤器函数
return v1 * v2
@register.simple_tag
def my_input(id,arg): # 自定义标签函数
result = "" %(id,arg,)
return mark_safe(result)
4、在使用自定义simple_tag和filter的index.html文件中导入之前创建的 my_tags.py
# 在index.html文件中:
{% load my_tag %}
5、使用simple_tag和filter(如何调用)
# 在index.html文件中:
{% load my_tag %} # 导入自定义的过滤器
{{ 3|filter_multi:4 }} # 3:表示第一个参数,4:表示第二个参数,这种方式只能传2个值。my_tags.py中的filter_multi函数会接受这2个值,并做下一步处理
{% my_input 'id_test' 'class_test' %} # 给自定义标签my_input传值。
7.5、模板语法(标签)的使用:for标签 {%%} -循环渲染
在Python里面的用法:
def template(request):
###########标签############
book_list = ["三国演义","金瓶梅","西游记"]
dic={"name":"sudada",
"age":18,
"sex":"male",
}
return render(request,"templates.html",locals())
#或者使用这种方式
return render(request,"books.html",{"book_list":book_list})
# {"book_list":book_list} == locals()
前端HTML代码使用是效果展示:
{% for n in book_list %} # for 循环开始,针对列表循环
{{ n }}
{% endfor %} # for 循环结束,固定语法
三国演义
金瓶梅
西游记
{% for book in book_list %}
{{ book }}
{% endfor %}
*三国演义
*金瓶梅
*西游记
{% for i in book_list %}
{{ forloop.counter }} {{ i }}
{% endfor %}
1 三国演义
2 金瓶梅
3 西游记
{% for key in dic %} # 针对字典循环
{{ key }}
# 拿到的值为字典的key
{% endfor %}
name
age
sex
{% for key,value in dic.items %} # 针对字典里面的key和value的循环
{{ key }} {{ value }}
{% endfor %}
name sudada
age 18
sex male
7.6、模板语法(标签)的使用:if标签-if条件判断
在Python里面的用法:
def template(request):
###########if 条件判断标签############
score=90
num_list=[123,34,546,8,98,2,344123,30,435457,65,456,4]
return render(request,"templates.html",locals())
前端HTML代码使用是效果展示:
if 标签
{% if score > 90 %}
very good
{% elif score > 60 %}
good
{% else %}
NO
{% endif %}
# 输出的值如下:
good
条件判断大于50的数字
# for循环里面嵌套if条件判断
{% for num in num_list %}
{% if num > 50 %}
{{ num }}
{% endif %}
{% endfor %}
# 输出的值如下:
123
546
98
344123
435457
65
456
7.7、Django引入静态文件
1、首先在项目根路径下创建 "static" 目录,然后把静态文件都放在这个目录下。
2、在settings.py文件的最后一行,新增"static"目录
# 别名:之后在使用时,可以用别名代替实际路径
STATIC_URL = '/static/' # 这个配置是Django自带就有的
# 文件的实际存在目录,给Django使用的
STATICFILES_DIRS=[
os.path.join(BASE_DIR,"static")
]
3、在前端html文件中引用静态文件
Title
# 引用免费CDN上面的js文件
# 引用static目录下的静态文件
7.8、Django模板的继承
Django模版引擎中最强大也是最复杂的部分就是模版继承了。模版继承可以让您创建一个基本的“骨架”模版,它包含您站点中的全部元素,并且可以定义能够被子模版覆盖的 blocks 。
1、继承的目的就是减少前端代码冗余
2、Django模板继承大体就是:先写一个父类HTML,然后子类HTML继承父类HTML的代码的方式。 具体如下:
2.1 父类HTML ,先写一堆父类HTML代码,然后定义一个 "block" (具体写法为:{% block Title %} )。"block"就是一个子类HTML可重写代码的部分。
{# 父类HTML文件base.html #}
{# 继承的写法#}
{% block Title %}
Title
{% endblock %}
{# 使用这套布局方式 #}
Panel title
Panel content
{% block centent %} {# block的功能:当其他的html文件继承base.html(当前文件)时,可以重写centent的内容。 #} {# centent这个名字不是固定写法 #}
这是一个盒子
{% endblock %}
2.2 子类HTML ,继承父类HTML的方法 (只能继承一个父类HTML模板)
1). 在子类HTML中,使用{% extends "base.html" %} 明确继承哪个父类HTML
2). 在子类HTML中,使用{% block centent %} 自定义代码
{# 子类HTML文件order.html #}
{% extends "base.html" %} {# 继承base.html文件,必须放在第一位 #}
{% block centent %} {# 然后重写block里面的内容 #}
订单列表
{% for order in order_list %}
{{ order }}
{% endfor %}
{% endblock %}
3、在子类HTML中使用{% block centent %}重写HTML后,还想要显示父类HTML中的{% block centent %},这种需要该如何实现。
{% extends "base.html" %}
{% block centent %}
商品列表
{% for shopper in shopper_list %}
{{ shopper }}
{% endfor %}
{{ block.super }} {# 写一个div标签,然后加上"{{ block.super }}"就可以了 #}
{% endblock %}
4、使用继承的一些注意事项
1).如果你在模版中使用 {% extends %} 标签,它必须是模版中的第一个标签。其他的任何情况下,模版继承都将无法工作。
2).在base模版中设置越多的 {% block %} 标签越好。请记住,子模版不必定义全部父模版中的blocks,所以,你可以在大多数blocks中填充合理的默认内容,然后,只定义你需要的那一个。多一点钩子总比少一点好。
3).如果你发现你自己在大量的模版中复制内容,那可能意味着你应该把内容移动到父模版中的一个 {% block %} 中。
4).为了更好的可读性,你也可以给你的 {% endblock %} 标签一个 名字 。例如:
{% block content %}
...
{% endblock content %}
5).在大型模版中,这个方法帮你清楚的看到哪一个 {% block %} 标签被关闭了。
6).最后,请注意您并不能在一个模版中定义多个相同名字的 block 标签。这个限制的存在是因为block标签的作用是“双向”的。这个意思是,block标签不仅提供了一个坑去填,它还在 _父模版_中定义了填坑的内容。如果在一个模版中有两个名字一样的 block 标签,模版的父模版将不知道使用哪个block的内容。