Django框架
一、Django框架介绍
- django框架是一个web框架, 而且是一个后端框架程序, 它不是服务器, 需要注意
- django框架帮我们封装了很多的组件, 帮助我们实现各种功能, 具有很强的扩展性.
- Django适用大项目更好。flask小项目,轻便
工作流程
- Django设计模式MVT。Django也遵循MVC思想,但是有⾃⼰的⼀个名词,叫做MVT
- Django的接收、返回请求的生命周期,MVT是其中的一部分
- M全拼为Model,数据库交互的,并向回馈反映给View,负责和数据库交互,进行数据处理。用于封装与应用程序的业务逻辑相关的数据及对数据的处理方法,是Web应用程序中用于处理应用程序的数据逻辑的部分,Model只提供功能性的接口,通过这些接口可以获取Model的所有功能。白话说,这个模块就是Web框架和数据库的交互层。
- V全拼为View,用View接受请求 ,接收请求,进行业务处理,返回应答。将数据与HTML语言结合起来的引擎
- T全拼为Template,Templates把View数据渲染出来,负责封装构造要返回的html。负责实际的业务逻辑实现
Django开发原则
- 快速开发和DRY原则。Do not repeat yourself.不要⾃⼰去重复⼀些⼯作。
官⽹⼿册介绍
- Django的官⽹:https://www.djangoproject.com/
- Django Book2.0版本的中⽂⽂档:http://djangobook.py3k.cn/2.0/chapter0 1/
二、Django框架搭建
(一)环境搭建
步骤
- 1.创建一个文件夹作为项目文件夹
- 2.系统环境变量的设置:WORKON_HOME
- 3. cmd进入你的项目文件夹,下载pipenv
- 4.pipenv shell 生成你的虚拟环境
- 5.下载django 2.2的版本,pip install Django==2.2
- 6.pycharm里面配置生成的虚拟环境
为什么需要虚拟环境
- 到目前为止,我们所有的第三方包安装都是直接通过 pip install xxx 的方式进行安装的,这样安装会将那个包安装到你的系统级的 Python环境中。但是这样有一个问题,就是如果你现在用 Django 1.10.x 写了个网站,然后你的领导跟你说,之前有一个旧项目是用 Django 0.9 开发的,让你来维护,但是 Django 1.10 不再兼容 Django 0.9 的一些语法了。这时候就会碰到一个问题,我如何在我的电脑中同时拥有 Django 1.10 和 Django 0.9 两套环境呢?这时候我们就可以通过虚拟环境来解决这个问题。
(二)项目实例
1.创建项目
- 方法一:.cmd通用
- django-admin startproject 项目名
- 方法二:.专业版pycharm
- create project里面直接选择
2.运行项目—manage.py入口文件,启动
- 运行项目两种方法
- 方法一:终端运行
- python manage.py runserver 端口号(可以不加,默认端⼝号是8000)
- 方法二:直接运行manage.py文件
- 将manage.py文件的在edit configurations中设置parameters ----设置为runserver,直接运行文件就可以启动文件
- 不添加参数,直接运行会显示manage.py help的帮助文档,并不会运行项目,python manage.py help也可以查看帮助文档
- 方法一:终端运行
- 说明:
- 只要生成了项目文件,就可以运行了,这样可以在本地访问你的⽹站,默认端⼝号是8000,这样就可以在浏览器中通过打开浏览器访问 http://127.0.0.1:8000/
- runserver是固定的,flask可以自定义启动命令
3.迁移数据库—manage.py迁移
- 方法
- python manage.py migrate ----迁移数据库
- 为什么没有启动数据库,但却可以执行迁移?
- Django默认使用sqlite3(settings中设置的)—小,简单,追求磁盘运行效率,mysql是高并发功能多的,单机话使用sqlite3还是不错的
- 如果换成mysql还是要启动的
- 迁移: 将模型迁移到数据库中
三、项⽬结构介绍
项目文件夹结构
├── 项目名
│ ├── __init__.py
│ ├── settings.py (项目配置文件)
│ ├── urls.py (项目路由)
│ └── wsgi.py (python网关)
├── manage.py (脚手架)
├── db.sqlite3 (数据库)
└── templates (模板目录)
manage.py:
- 以后和项⽬交互基本上都是基于这个⽂件。⼀般都是在终端输⼊ python manage.py [⼦命令]。可以输⼊python manage.py help看下能做什 么事情。除⾮你知道你⾃⼰在做什么,⼀般情况下不应该编辑这个⽂件。
settings.py:
- 本项⽬的设置项,以后所有和项⽬相关的配置都是放在这个⾥ ⾯。
urls.py:
- 这个⽂件是⽤来配置URL路由的。⽐如访问http://127.0.0.1/news/ 是访问新闻列表⻚,这些东⻄就需要在这个⽂件中完成。
wsgi.py:
- 项⽬与WSGI协议兼容的web服务器⼊⼝,部署的时候需要⽤到的, ⼀般情况下也是不需要修改的。
app应用文件夹
project和app的关系
- app是django项⽬的组成部分。⼀个app代表项⽬中的⼀个模块,所有URL请求 的响应都是由app来处理。⽐如⾖瓣,⾥⾯有图书,电影,⾳乐,同城等许许多多的模块,如果站在django的⻆度来看,图书,电影这些模块就是app,图 书,电影这些app共同组成⾖瓣这个项⽬。因此这⾥要有⼀个概念,django项⽬由许多app组成,⼀个app可以被⽤到其他项⽬,django也能拥有不同的 app
- 一个app实现某个功能或者模块,比如用户模块,订单模块;
一个project是配置文件和多个app的集合,这些app组合成整个站点;
一个project可以包含多个app; - 为什么创建app:就是为了将不同功能的代码分开,分成一个个的文件来管理
好管理,开发比较方便 好维护
创建app
- cmd下运行:python manage.py startapp [app名称]
app中的⽂件:
__init__.py 说明⽬录是⼀个Python模块 ,作用:在这里做声明 models.py 写和数据库相关的内容 views.py 写视图函数。接收请求,处理数据 与M和T进⾏交互 tests.py 写测试用例。写测试代码的⽂件(暂时不需要关⼼) admin.py 后台管理有关。⽹站后台管理相关的
应⽤注册
- 建⽴应⽤和项⽬之间的联系,需要对应⽤进⾏注册。
- 修改settings.py中的INSTALLED_APPS配置项
DEBUG模式
- 默认开启了debug模式,那么修改代码,然后按下ctrl+s,那么Django会⾃动重启项⽬。
Django项⽬中代码出现了问题,在浏览器中和控制台中会打印错误信息 - 如果项⽬上线了,关闭debug模式,不然有很⼤的安全隐患,关闭DEBUG模式,在setting⽂件中,将DEBUG = False
(一)URL与视图
- 数据表创建好了,现在需要我们的页面了,Django如何载入页面呢?
- 在view.py文件下就可以创建咱们的视图逻辑了
- 这里咱们使用类的方式来写,当然也可以用函数的方式来写 这里我更推荐使用类的方式.
- 用户访问浏览器,一般两种方式,get获取网页和post提交数据,get也可以提交数据,以一种明文形式显示在url中,post提交的数据url中不显示,一种安全的数据提交方式,get方式提交数据一般应用于一些排序方式和类别过滤中,post用于用户提交的表单数据,比较隐私的数据,get方式提交数据为小数据信息,而post方式提交数据可以是大数据信息
- 由于django会有CSRF验证所以我们在提交表单的时候要构建一个csrf的token,这里django提供了方法让我们直接构建出一条token
1)视图的定义
- 视图⼀般都写在app的views.py中。
- 特点:
- 第⼀个参数必须是
request对象
- (⼀个HttpRequest)这个对象存储了请求过来的所有信息,包 括携带的参数以及⼀些头部信息等
- 在视图中,⼀般是完成逻辑相关的操作。 ⽐如这个请求是添加⼀篇博客,那么可以通过request来接收到这些数据,然后存储到数据库中,最后再把执⾏的结果返回给浏览器
- return返回结果必须是
HttpResponseBase
对象或者⼦类的对象。-----定义应用news/views.py----- from django.http import HttpResponse def news(request): return HttpResponse("新闻!") -----注册应用urls.py------ from news import views urlpatterns = [ path("news",views.news) ]
- 第⼀个参数必须是
2)路由的定义
URL映射
作用
:- 视图写完后,要与URL进⾏映射,也即⽤户在浏览器中输⼊什么url的时候可以请求到这个视图函数。在⽤户输⼊了某个url,请求到我们的⽹站的时候, django会从项⽬的urls.py⽂件中寻找对应的视图。在urls.py⽂件中有⼀个 urlpatterns变量,以后django就会从这个变量中读取所有的匹配规则。匹配规 则需要使⽤django.urls.path函数进⾏包裹,这个函数会根据传⼊的参数返回 URLPattern或者是URLResolver的对象。
- 实现绑定视图函数
实现
:django.urls.path-----urls.py------ from django.contrib import admin from django.urls import path from book import views urlpatterns = [ path('admin/', admin.site.urls), path('book/',views.book_list) ]
re_path函数
:有时候我们在写url匹配的时候,想要写使⽤正则表达式来实现⼀些复杂的需 求,那么这时候我们可以使⽤re_path来实现。re_path的参数和path参数⼀模 ⼀样,只不过第⼀个参数也就是route参数可以为⼀个正则表达式。- route参数
- $表示结束匹配
- ()给分组。
- 固定写法?P<变量> 给分区取名:(?P\d{4})
- route参数
3)URL模块化
模块化原因:
- 因为当有多个app的时候,每个都对应一个view,在总urls每个导入就必须重命名,会很麻烦,所以需要模块化,把每个app新建一个urls文件,把路由放到里面,然后在总的urls导入这个app文件夹就行
- URL中包含另外⼀个urls模块:在我们的项⽬中,不可能只有⼀个app,如果把所有的app的views中的视图都 放在urls.py中进⾏映射,肯定会让代码显得⾮常乱。因此django给我们提供了 ⼀个⽅法,可以在app内部包含⾃⼰的url匹配规则,⽽在项⽬的urls.py中再统 ⼀包含这个app的urls。使⽤这个技术需要借助include函数。
实现方法:include
------urls.py⽂件-------- from django.contrib import admin from django.urls import path,include urlpatterns = [ path('admin/', admin.site.urls), path('book/',include("book.urls")) ##以后在请求book的app相关的url的时候都需要加⼀个book的前缀。 ##这里的路由与app的路由拼接,最后形成最终的url ] ------book/urls.py⽂件-------- from django.urls import path from . import views urlpatterns = [ path('', views.index), path('sign/', views.login) ]
4)URL添加参数
作用
:- 有时候,url中包含了⼀些参数需要动态调整。⽐如简书某篇⽂章的详情⻚的 url,是https://www.jianshu.com/p/a5aab9c4978e后⾯的a5aab9c4978e 就是这篇⽂章的id,那么简书的⽂章详情⻚⾯的url就可以写成 https://www.jianshu.com/p/,其中id就是⽂章的id。那么如何在django中实 现这种需求呢。这时候我们可以在path函数中,使⽤尖括号的形式来定义⼀个 参数。⽐如我现在想要获取⼀本书籍的详细信息,那么应该在url中指定这个参数。
特点
:- 路由的严格的开始和严格的结束
- Django前面不加,结尾必须加/
- flask必须前面加/ ,结尾加与不加会有区别,但可以选择
- 路由的严格的开始和严格的结束
参数传递的两种方法
:- <>尖括号:这类参数定义的话就必须传进去,路由和视图函数都需要定义参数
- ?关键字参数:路由不需要定义参数,视图函数不需要传参,是通过
request.GET.get("") 拿到关键字参数的值
URL映射--路由的传参---urls.py
- path传递参数:
- <>尖括号:‘book/<book_id>/’
- re_path传递参数:
- 尖括号:r"^article_list/(?P\d{2})/" 这里()给分组。固定写法?P<变量> 给分区取名
- path传递参数:
- 视图函数—views.py
- <>尖括号: def book_detail(request,book_id):
- ?关键字参数:request.GET.get(“id”)
''' <>尖括号 ''' -----book/urls.py------ urlpatterns = [ path('<book_id>/',views.book_detail) re_path(r"(?P<year>\d{4})/",views.article_list) ] -----book/views.py----- def book_detail(request,book_id): text = "您输⼊的书籍的id是:%s" % book_id 14 return HttpResponse(text) def current_year(request, year): return HttpResponse('年份是%s' % year) ''' ?关键字参数 ''' -----urls.py------ from book import views urlpatterns = [ path('admin/', admin.site.urls), path('book/detail/',views.book_detail) ] -----book/views.py----- def book_detail(request): book_id = request.GET.get("id") text = "您输⼊的书籍id是:%s" % book_id return HttpResponse(text)
URL反转传递参数
作用:
利用当前url,添加参数,可以是适用于重定向的返回的url改变实现:
- <>尖括号:kwargs来传递参数。例如:reverse(“book:detail”,kwargs={“book_id”:1})
- ?关键字:直接拼接,例如reverse(“front:singin”) + “?name=jr”
- 因为django中的reverse反转url的时候不区分GET请求和POST请求,因此不能在反转的时候添加查询字符串的参数。如果想要添加查询字符串的参数,只能 ⼿动的添加。
5)url命名
为什么需要URL命名
:因为在项⽬开发的过程中URL地址可能经常变动,如果写死会经常去修改,指定了命名就可以修改视图函数了和视图函数的url如何给⼀个URL指定名称
:path(‘login/’, views.login) 改为path(‘signIn/’, views.login, name=“login”),这样我们并不需要因为改变了路由就需要将视图函数改变应⽤命名空间
:在多个app之间可能产⽣同名的URL,即 name是同样的,这时候为了避免这种情况,可以使⽤ 命名空间来加以区分。在urls.py中添加app_name即可------front\urls.py------ from django.urls import path from . import views # 这个就是应用命名空间 app_name = 'front' urlpatterns = [ path('', views.index), path('signIn/', views.login, name='login'), ] ------front\views.py------ from django.shortcuts import render, redirect from django.http import HttpResponse def index(request): name = request.GET.get('name') if name: return HttpResponse('前台首页') else: return redirect('front:login') def login(request): return HttpResponse('前台登录页面')
实例命名空间
作用:
- ⼀个app,可以创建多个实例。可以使⽤多个URL映射同⼀个App。在做反转的时候,如果使⽤应⽤命名空间,就会发⽣混淆,为了避免这个问题,可以使⽤实例命名空间,实例命名空间使⽤,namespace=‘实例命名空间’
- 然后在函数里面就可以拿到路由名
实现:
namespace=‘实例命名空间’""" 实例命名空间namespace """ ------urls.py⽂件-------- from django.contrib import admin from django.urls import path,include urlpatterns = [ path('admin/', admin.site.urls), path('cms1/', include("cms.urls",namespace='cms1')), path('cms2/', include("cms.urls",namespace='cms2')), ] ------cms/views.py⽂件-------- current_namespace = request.resolver_match.namespace print(current_namespace)
(二)模板
模板介绍
- 在之前的章节中,视图函数只是直接返回⽂本,⽽在实际⽣产环境中其实很少 这样⽤,因为实际的⻚⾯⼤多是带有样式的HTML代码,这可以让浏览器渲染出 ⾮常漂亮的⻚⾯。DTL是Django Template Language三个单词的缩写,也就 是Django⾃带的模板语⾔。当然也可以配置Django⽀持Jinja2等其他模板引 擎,但是作为Django内置的模板语⾔,和Django可以达到⽆缝衔接⽽不会产⽣ ⼀些不兼容的情况。
DTL与普通的HTML⽂件的区别
- DTL模板是⼀种带有特殊语法的HTML⽂件,这个HTML⽂件可以被Django编 译,可以传递参数进去,实现数据动态化。在编译完成后,⽣成⼀个普通的 HTML⽂件,然后发送给客户端。
渲染模板步骤
首先:
模板选择(都需要配置)- 总模板开启:
------settings.py 中TEMPLATES-------- # DIRS优先级高于APP_DIRS。DIRS就是总模板。APP_DIRS就是开启应用模板 # 默认DIRS为[],应用模板开启,添加os.path.join(BASE_DIR, 'templates')就是说明会在总模板的文件夹中找 'DIRS': [os.path.join(BASE_DIR, 'templates')], 'APP_DIRS': True,
- 某应用的模板开启
------settings.py 中TEMPLATES-------- # 默认APP_DIRS是开启的,但是应用还需要注册,总模板如果开启的话会先找它,因为优先级更大 # APP_DIRS:默认为True,这个设置为True后,会在INSTALLED_APPS的安 装了的APP下的templates⽂件加中查找模板。settings.py中 INSTALLED_APPS数组中添加你的app名字 'DIRS': [], 'APP_DIRS': True, ------settings.py 中INSTALLED_APPS------- # 往列表中添加某应用名称 'book'
- 总模板开启:
其次:
模板加载,方式两种:- 1.render_to_string:找到模板,然后将模板编译后渲染成Python的字符串格 式。最后再通过HttpResponse类包装成⼀个HttpResponse对象返回回去。
from django.template.loader import render_to_string from django.http import HttpResponse def book_detail(request,book_id): html = render_to_string("index.html") return HttpResponse(html)
- 2.以上⽅式虽然已经很⽅便了。但是django还提供了⼀个更加简便的⽅式,直接将模板渲染成字符串和包装成HttpResponse对象⼀步到位完成
from django.shortcuts import render def book_list(request): return render(request,'index.html')
- 1.render_to_string:找到模板,然后将模板编译后渲染成Python的字符串格 式。最后再通过HttpResponse类包装成⼀个HttpResponse对象返回回去。
查找顺序:
- 先在DIRS这个列表依次查找路径下查找模板
- 再检查当前这个视图所处的app是否已经安装,如果已经安装了,那么就先在当前这个app下的templates⽂件夹中查找模板
- 如果没有找到,那么会在其他已经安装了的app中查找。如果所有路径下都没有找到,那么会抛出⼀ 个TemplateDoesNotExist的异常
模板传参
- 模板中可以包含变量,Django在渲染模板的时候,可以传递变量对应的值过去 进⾏替换。变量的命名规范和Python⾮常类似,只能是阿拉伯数字和英⽂字符 以及下划线的组合,不能出现标点符号等特殊字符。变量需要通过视图函数渲 染,视图函数在使⽤render或者render_to_string的时候可以传递⼀个context 的参数,这个参数是⼀个字典类型
- 字典里面键值存储的对象可以是:字符串、字典、列表(元组)、类实例对象。取值取不到的话标签就不会显示
- 键值是字典:.key取值
- 键值是列表(元组):.0取值(.索引)
- 键值类实例对象:.属性取属性值
- 不能通过中括号的形式访问字典和列表中的值,dict[‘key’]和list[1]是不 ⽀持的!
--------views.py-------- def profile(request): return render(request,'profile.html',context={'username':'juran'}) class Person(object): def __init__(self,username): self.username = username def index(request): p = Person("居然") content = { 'person':p } return render(request,"index.html",context=content) -------profile.html----- <h1>{ { username }}</h1> -------index.html----- <h1>{ { person.username }}</h1>
常⽤的模板标签
- 更多标签:https://docs.djangoproject.com/en/2.0/ref/templates/builtins/
1)if标签
- if标签相当于Python中的if语句,有elif和else相对应,但是所有的标 签都需要⽤标签符号({%%})进⾏包裹。if标签中可以使⽤==、!=、<、<=、 >、>=、in、not in、is、is not等判断运算符。
- 必须以{% endif %}结尾
2)for…in…标签
- for…in…标签:类似于Python中的for…in…。可以遍历列表、元 组、字符串、字典等⼀切可以遍历的对象。
{% for book in books %} <p>{ { book }}</p> {% endfor %} --------反向遍历reversed------ {% for book in books reversed %} <p>{ { book }}</p> {% endfor %}
- 1.遍历字典的时候,需要使⽤items、keys和values等⽅法。在DTL中,执⾏⼀个 ⽅法不能使⽤圆括号的形式。
{% for key,value in person.items %} <p>key:{ { key }}</p> <p>value:{ { value }}</p> {% endfor %}
- 2.在for循环中,DTL提供了⼀些变量可供使⽤,用来标识每一次的循环信息
forloop.counter:当前循环的下标。以1作为起始值。 forloop.counter0:当前循环的下标。以0作为起始值。 forloop.revcounter:当前循环的反向下标值。⽐如列表有5个元素,那么第⼀次遍历这 个属性是等于5,第⼆次是4,以此类推。并且是以1作为最后⼀个元素的下标。 forloop.revcounter0:类似于forloop.revcounter。不同的是最后⼀个元素的下标 是从0开始。 forloop.first:是否是第⼀次遍历。 forloop.last:是否是最后⼀次遍历。 forloop.parentloop:如果有多个循环嵌套,那么这个属性代表的是上⼀级的for循环
- 3.for…in…empty标签:这个标签使⽤跟for…in…是⼀样的,只不过是在遍历的 对象
如果没有元素的情况下,会执⾏empty中的内容。
{% for person in persons %} <li>{ { person }}</li> {% empty %} 暂时还没有任何⼈ {% endfor %}
- 4.注意:在for循环中,
break,continue语句是⽤不了的。
- 1.遍历字典的时候,需要使⽤items、keys和values等⽅法。在DTL中,执⾏⼀个 ⽅法不能使⽤圆括号的形式。
3)a标签
- a标签:在模版中,我们经常要写⼀些url,⽐如某个a标签中需要定义
href属性
。- 写死:当然如果通过硬编码的⽅式直接将这个url写死在⾥⾯也是可以的。但是这样对于以后项⽬维护可能不是⼀件好事。建议使⽤这种反转的⽅式来实现,
- 反转的⽅式:
- 一般:<a href="{% url ‘book:list’ %}">图书列表⻚⾯
- 传参:传递多个参数,通过空格的⽅式进⾏分隔。
- <>尖括号:
- 使⽤位置参数:<a href="{% url ‘book:detail’ 1 %}">图书详情⻚⾯
- 使⽤关键字参数: <a href="{% url ‘book:detail’ book_id=1 %}">图书详情⻚⾯
- ?关键字:<a href="{% url ‘book:detail’ book_id=1 %}?page=1">图书详情⻚⾯
- <>尖括号:
模板常⽤过滤器
- 在模版中,有时候需要对⼀些数据进⾏处理以后才能使⽤。⼀般在Python中我 们是通过函数的形式来完成的。⽽在模版中,则是通过过滤器来实现的。过滤 器使⽤的是|来使⽤。
- add
定义:
将传进来的参数添加到原来的值上⾯。这个过滤器会尝试将值和参数int强转成整形,然后进⾏相加。如果强转失败了,那么会将值和参数进⾏拼接,直接相加。如果是字符串,那么会拼接成字符串,如果是列表,那么会拼接成⼀个列表。-------templates\index.html--------- { { value|add:"2" }} ## 如果value是等于4,那么结果将是6。如果value是等于⼀个普通的字符串,⽐ 如abc,那么结果将是abc2
- cut
定义:
移除值中所有指定的字符串。类似于python中的replace(args,"")。-------templates\index.html--------- { { value|cut:" " }}
- date
定义:
将⼀个⽇期按照指定的格式,格式化成字符串。有默认的格式,可以修改成自己想要的-------templates\index.html--------- { { birthday|date:"Y/m/d" }} ------views.py------------ from django.shortcuts import render def book_list(request): context = {"birthday": datetime.now()} return render(request,'index.html',context=content)
- default
定义:
如果值被评估为False。⽐如[],"",None,{}等这些在if判断中为False的值, 都会使⽤default过滤器提供的默认值。-------templates\index.html--------- { { value|default:"nothing" }} ## 如果value是等于⼀个空的字符串。⽐如"",那么以上代码将会输出nothing。
- first/last
定义:
返回列表/元组/字符串中的第⼀个元素/最后⼀个元素。-------templates\index.html--------- { { value|first }} { { value|last }}
- floatformat
定义:
使⽤四舍五⼊的⽅式格式化⼀个浮点类型。如果这个过滤器没有传递任何参 数。那么只会在⼩数点后保留⼀个⼩数,如果⼩数后⾯全是0,那么只会保留整 数。当然也可以传递⼀个参数,标识具体要保留⼏个⼩数。-------templates\index.html--------- <li>{ { 34.32|floatformat }}</li> 34.3 2 <li>{ { 34.35|floatformat }}</li> 34.4 3 <li>{ { 34.353333|floatformat:3}}</li> 34.353
- join
定义:
类似与Python中的join,将列表/元组/字符串⽤指定的字符进⾏拼接.-------templates\index.html--------- { { value|join:"/" }} ## 如果value是等于['a','b','c'],那么以上代码将输出a/b/c。
- ength
定义:
获取⼀个列表/元组/字符串/字典的⻓度。-------templates\index.html--------- {