Python的WEB框架有Django、Tornado、Flask 等多种,Django相较与其余WEB框架其优点为:大而全,框架自己集成了ORM、模型绑定、模板引擎、缓存、Session等诸多功能。php
MVC介绍:html
M:model,模型,是应用程序中用于处理应用程序数据逻辑的部分,主要是负责对数据库进行读写。前端
V:view,视图,是应用程序中处理数据显示的部分,一般视图是依据模型中的数据建立的。python
C:controller,控制器,是应用程序处理与用户交互的部分,一般控制器负责从视图中去读取数据,也向模型去发送数据。git
MTV与MVC二者区别与联系:web
MTV与MVC这两种模式没有根本上的区别,他们都是让复杂的程序在各个组件之间保持松耦合关系,区别只是名字不一样,叫法不一样而已。正则表达式
MTV介绍:shell
M:Model(模型):负责业务对象与数据库的对象(ORM)数据库
T:Template(模版):负责如何把页面展现给用户django
V:View(视图):负责业务逻辑,并在适当的时候调用Model和Template
另外,Django还有一个url分发器,它的做用是将一个个URL的页面请求分发给不一样的view处理,view再调用相应的Model和Template
注:本篇博客采用的是django2.0介绍
django简易流程图:
django简单安装配置
django #安装: pip3 install django 添加环境变量 #1 建立project django-admin startproject mysite ---mysite ---settings.py ---url.py ---wsgi.py ---- manage.py(启动文件) #2 建立APP python mannage.py startapp app01 #3 settings配置 TEMPLATES STATICFILES_DIRS=( os.path.join(BASE_DIR,"statics"), ) STATIC_URL = '/static/' # 咱们只能用 STATIC_URL,但STATIC_URL会按着你的STATICFILES_DIRS去找#4 根据需求设计代码 url.py view.py #5 使用模版 render(req,"index.html") #6 启动项目 python manage.py runserver 127.0.0.1:8090 #7 链接数据库,操做数据 model.py
若是用pycharm能够直接建的哦!
目录详细解释:
若是用命令行建立,只会有如下几个目录:
django-admin.py startproject mysite
django-admin.py 是Django的一个用于管理任务的命令行工具,manage.py是对django-admin.py的简单包装,每个Django Project里都会有一个mannage.py。
manage.py ----- Django项目里面的工具,经过它能够调用django shell和数据库等。
settings.py ---- 包含了项目的默认设置,包括数据库信息,调试标志以及其余一些工做的变量。
urls.py ----- 负责把URL模式映射到应用程序。
用python manage.py startapp app
运行python manage.py runserver 8000 或者直接用pycharm运行
此时,django已经安装成功
如今咱们就写一个例子:
mysite的urls:
from django.contrib import admin from django.urls import path,include urlpatterns = [ path('admin/', admin.site.urls), path('app01',include('app01.urls')), ]
app01的urls:
from django.urls import path from . import views urlpatterns = [ path('', views.index, name='index'), ]
app01的views:
from django.shortcuts import render from django.http import HttpResponse def index(request): return HttpResponse("Hello, ylqh.")
访问:
第一个简易的django流程完成
URL配置(URLconf)就像Django 所支撑网站的目录。是高质量Web应用程序中的一个重要细节,其实质就是经过url指到相应的视图函数
Django可让你设计URL,没有.php
或没有.cgi
要求。
url()函数能够传递4个参数,其中2个是必须的:正则和view,以及2个可选的参数:kwargs和name
urlpatterns = [
path(正则表达式, views视图函数,参数,别名),
]
参数说明:
1:正则表达式,它是一种匹配字符串或url地址的语法
2:一个可调对象,一般为一个视图函数或者一个指定视图函数的字符串。若是是简单捕获,那么捕获的值将做为一个位置参数进行传递,若是是命名捕获,那么将做为一个关键字参数。
3:可选的任意数量的关键字参数能够做为一个字典传递给目标视图。
4:可选的name参数,对你的URL进行命名,可让你可以在Django的任意处,尤为是模板内显式地引用它。至关于给URL取了个全局变量名,你只须要修改这个全局变量的值,在整个Django中引用它的地方也将一样得到改变
django1.x 系列:
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^articles/2018/$', views.special_case_2018), #url(r'^articles/[0-9]{4}/$', views.year_archive), url(r'^articles/([0-9]{4})/$', views.year_archive), #no_named group url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail), ]
dgango2.0 系列:
urlpatterns = [ path('index/', views.index), path('articles/2018/', views.special_case_2018), path('articles/<int:year>/', views.year_archive), path('articles/<int:year>/<int:month>/', views.month_archive), path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail), ]
注意:1:要从url中捕获值,请使用尖括号:<>
2:捕获的值能够选择包含转换器类型。例如:<int : name> 捕获整数参数。
3:没有必要添加一个前斜杠,例如:articles 不是 /articles。
示例请求:
/articles/2018/03/
匹配列表中的第三个条目。Django会调用这个函数 。views.month_archive(request, year=2018,month=3)
/articles/2018/
会匹配列表中的第一个模式,而不是第二个模式,由于模式是按顺序传参的,而第一个模式是第一个要传递的参数。在这里,Django会调用这个函数 views.special_case_2018(request)
/articles/2018/03/subao/
将匹配最终模式。Django会调用这个函数 。views.article_detail(request, year=2018, month=3, slug="subao")
2.路径转换器:
如下路径转换器默承认用:
str- 匹配任何非空字符串,不包括路径分隔符'/'。默认的转换器不包含在表达式中。 int - 匹配零或任何正整数。返回一个int值法、。 slug - 匹配由ASCII字母或数字组成的字符串,以及加上-字符和下划线字符。例如:subao-yunwei-kaifa。 uuid - 匹配格式化的UUID。为防止多个URL映射到同一页面,必须包含破折号,而且字母必须是小写。例如,075194d3-6885-417e-a8a8-6c931e272f00。返回一个 UUID实例。 path- 匹配任何非空字符串,包括路径分隔符 '/'。这使您能够匹配完整的URL路径,而不只仅是URL路径的一部分字符串。
自定义路径转换器
当默认的Path Converter不能知足需求时,Django2.0支持用户注册自定义的Path Converter。
Path Converter是一个类,定义Converter类须要包含下面的属性或方法:
regex属性,字符串类型。
to_python(self,value),它处理将匹配的字符串转换成应该传递到视图函数的类型。若是它不能转换特定的值,则报ValueError。
to_url(self,value):和 to_python 相反,它会将Python类型转换为在URL中使用的字符串
示例:
app01/urls.py from django.urls import register_converter,path from app01 import views,converters urlpatterns = [ path('articles/<yyyy:year>/', views.year_yyyy), path('articles/<int:year>/', views.year_archive), ]
converters.py class FourDigitYearConverter: regex = '[0-9]{4}' def to_python(self, value): return int(value) def to_url(self, value): return '%04d' % value
views.py def year_yyyy(request,year): return HttpResponse("hello yyyy" + str(year)) def year_archive(request,year): return HttpResponse("hello year" + str(year))
请求示例:
Django2.0也支持咱们使用正则表达式来捕获值。注意,用正则表达式捕获值,须要使用re_path(),而不是前面介绍的path()。
正则表达式建议使用命名正则表达式组,语法以下:
(?P<name>pattern)
尖括号里的name为分组名,pattern为正则表达式。
前面的示例可使用正则表达式修改成:
from django.urls import path, re_path from . import views urlpatterns = [ path('articles/2018/', views.special_case_2018), re_path('articles/(?P<year>[0-9]{4})/', views.year_archive), re_path('articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/', views.month_archive), re_path('articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[\w-_]+)/', views.article_detail), ]
这里与前面的例子的不一样点:
1.这里的代码匹配更加严格,好比:year为10001就没法匹配,由于它超出了正则规定的4位数
2.传给view函数的参数为字符串类型,这点和 Django使用url 是同样的
简单介绍未命名的正则表达式组(这种方式不推荐使用!):
除了命名组的语法,例如:(?P<year>[0-9]{4}),相对应的未命名的语法:([0-9]{4})
请求的URL被看作是一个普通的Python字符串,URLconf在其上查找并匹配。进行匹配时将不包括GET或POST请求方式的参数以及域名。
例如,在https://www.example.com/myapp/
的请求中,URLconf将查找myapp/
。
在https://www.example.com/myapp/?page=3
的请求中,URLconf也将查找myapp/
。
URLconf不检查使用何种HTTP请求方法,全部请求方法POST、GET、HEAD等都将路由到同一个URL的同一个视图。在视图中,才根据具体请求方法的不一样,进行不一样的处理。
一个小技巧是为视图的参数指定默认参数,例子:app01/urls.py
app01/urls.py from django.urls import register_converter,path,re_path from app01 import views,converters urlpatterns = [ path(r'blog', views.page), path(r'blog/page<int:num>/', views.page),#django2.0 url(r'^blog/page(?P<num>[0-9]+)/$', views.page),#django1.x ] views.py def page(request,num='1'): return HttpResponse('hello'+str(num))
在上面的例子中,两个URL模式指向同一个视图views.page
。可是第一个模式不会从URL中捕获任何值。 若是第一个模式匹配,page()函数将使用num参数的默认值"1"。 若是第二个模式匹配,page()将使用捕获的num值
当Django找不到与请求匹配的URL时,或者当抛出一个异常时,将调用一个错误处理视图。错误视图包括400、40三、404和500,分别表示请求错误、拒绝服务、页面不存在和服务器错误。它们分别位于:
注意注意:这些值能够在根URLconf中设置。在其它app01中的二级URLconf中设置这些变量无效
Django有内置的HTML模版,用于返回错误页面给用户,可是这些403,404页面太难看了,一般咱们都自定义错误页面。
首先,在根URLconf中额外增长下面的条目:
# URLconf from django.conf.urls import url from . import views urlpatterns = [ url(r'^blog/', views.page), url(r'^blog/page<int:num>/', views.page), ] # 增长的条目 handler400 = views.bad_request handler403 = views.permission_denied handler404 = views.page_not_found handler500 = views.page_error
而后在视图中增长:
def page_not_found(request): return render(request, '404.html') def page_error(request): return render(request, '500.html') def permission_denied(request): return render(request, '403.html') def bad_request(request): return render(request, '400.html')
最后,你本身想要啥样的错误页面本身写就ok了。
通常状况,咱们会在每个app下面,各自建一个urls.py的路由模块,而后从跟路由出发,将app所包含的url请求,所有转发到相应的urls.py模块中,
下面是django自己的URLconf的摘录,它包含须要其余的urlconf:
urlpatterns = [ # ... snip ... path('community/', include('aggregator.urls')), path('contact/', include('contact.urls')), # ... snip ... ]
注意:这个例子中的正则表达式不包含$(字符串结束的匹配符),可是包含一个末尾的斜杠,每当django遇到include()方法的时候,他会截断与该点匹配的URL的部分,并将剩余的字符串发送给include的URLconf以供进一步处理,也就是转发到二级路由里面去。
另一种转发就是经过path()实例列表来包含url模式。如:
from django.urls import include, path from apps.main import views as main_views from credit import views as credit_views extra_patterns = [ path('reports/', credit_views.report), path('reports/<int:id>/', credit_views.report), path('charge/', credit_views.charge), ] urlpatterns = [ path('', main_views.homepage), path('help/', include('apps.help.urls')), path('credit/', include(extra_patterns)), ]
在这个例子中,/credit/reports/
URL将由credit_views.report()
Django视图处理 。这种作法等同于把二级路由模块内的代码移动到了跟路由模块里面了,不过不推荐这种方式!
看下面的示例:
from django.urls import path from . import views urlpatterns = [ path('<page_slug>-<page_id>/history/', views.history), path('<page_slug>-<page_id>/edit/', views.edit), path('<page_slug>-<page_id>/discuss/', views.discuss), path('<page_slug>-<page_id>/permissions/', views.permissions), ]
上面的路由,前缀的URLconf中存在冗余的现象,咱们能够改进下,只需声明共同的路径(前缀)一次,并将后面的部分转发:
from django.urls import include, path from . import views urlpatterns = [ path('<page_slug>-<page_id>/', include([ path('history/', views.history), path('edit/', views.edit), path('discuss/', views.discuss), path('permissions/', views.permissions), ])), ]
这样看着就舒服多了。
正则表达容许嵌套参数,Django将解析他们而且把它们传递给视图。当反转查询的时候,django将尝试填充全部外部捕获的参数,而忽略任何嵌套捕获的参数,
考虑下面的URL模式,能够选择使用页面参数
from django.urls import re_path urlpatterns = [ re_path(r'^blog/(page-(\d+)/)?$', blog_articles), # bad re_path(r'^comments/(?:page-(?P<page_number>\d+)/)?$', comments), # good ]
以上两种方式都是使用了嵌套参数,
# blog/page-1/ 将匹配page-1 并带有两个位置参数式page-1和1
# comments的模式将匹配page_number并带有一个关键字参数是1(这一个例子中外围参数是一个不捕获的参数(?:...))
视图须要最外层捕获的参数来反查,在这个例子中是comments或者没有参数,而能够不带参数或者用一个值来反查blog_articlespage-1/page_number
包含的URLconf从父URLconf接受捕获的任何参数,官网示例:
# In settings/urls/main.py from django.urls import include, path urlpatterns = [ path('<username>/blog/', include('foo.urls.blog')), ] # In foo/urls/blog.py from django.urls import path from . import views urlpatterns = [ path('', views.blog.index), path('archive/', views.blog.archive), ] 本身示例: #mysite/urls.py from django.contrib import admin from django.urls import path,include urlpatterns = [ path('admin/', admin.site.urls), path('<username>/',include('app01.urls')) ] #app01/urls.py from django.urls import path from app01 import views urlpatterns = [ path('',views.index), path('archive',views.archive), ] #app01/views.py from django.http import HttpResponse def index(request,username): return HttpResponse("Hello, %s" % username) def archive(request,username): return HttpResponse("Hello, %s " % username)
上面的两种url均可以捕获到变量,并传递给urlconf,最终传给视图
URLconf具备一个钩子(hook),容许你传递一个Python字典做为额外的关键字参数给视图函数
from django.urls import path from . import views urlpatterns = [ path('blog/<int:year>/', views.year_archive, {'foo': 'bar'}), ]
在上面的例子中,对于/blog/2005/
请求,Django将调用views.year_archive(request, year='2005', foo='bar')
。理论上,你能够在这个字典里传递任何你想要的传递的东西。可是要注意,URL模式捕获的命名关键字参数和在字典中传递的额外参数有可能具备相同的名称,这会发生冲突,要避免。
#mysite/urls.py from django.contrib import admin from django.urls import path,include urlpatterns = [ path('admin/', admin.site.urls), path('app01/',include('app01.urls')), ] #app01/urls.py from django.urls import register_converter,path,re_path from app01 import views,converters urlpatterns = [ path('<int:year>/',views.year_archive,{'foo':'bar'}) ] #app01/views.py from django.http import HttpResponse def year_archive(request,year,foo='bar'): print(year,foo) return HttpResponse("hello year")
相似上面,也能够传递额外的参数给include()。参数会传递给include指向的urlconf中的每一行
例如:下面的两个URLconf在功能上是相同的:
第一:官网配置: # main.py from django.urls import include, path urlpatterns = [ path('blog/', include('inner'), {'blog_id': 3}), ] # inner.py from django.urls import path from mysite import views urlpatterns = [ path('archive/', views.archive), path('about/', views.about), ] 本身验证: #mysite/urls.py from django.urls import include,path urlpatterns = [ path(r'blog/', include('app01.urls'),{'blog_id':3}), ] #app01/urls.py from django.urls import path from app01 import views urlpatterns = [ path('archive/',views.archive), path('about/',views.about), ] #app01/views.py from django.http import HttpResponse def archive(request,blog_id): return HttpResponse("Hello archive %s" % blog_id) def about(request,blog_id): return HttpResponse('hello about %s' % blog_id)
第二:
官网配置: # main.py from django.urls import include, path from mysite import views urlpatterns = [ path('blog/', include('inner')), ] # inner.py from django.urls import path urlpatterns = [ path('archive/', views.archive, {'blog_id': 3}), path('about/', views.about, {'blog_id': 3}), ] 本身验证: #mysite/urls.py from django.urls import include,path urlpatterns = [ path(r'blog/', include('app01.urls')), ] #app01/urls.py from django.urls import path from app01 import views urlpatterns = [ path('archive/',views.archive,{'blog_id':3}), path('about/',views.about,{'blog_id':3}), ] #app01/views.py from django.http import HttpResponse def archive(request,blog_id): return HttpResponse("Hello archive %s" % blog_id) def about(request,blog_id): return HttpResponse('hello about %s' % blog_id)
注意,只有当你肯定被include的URLconf中的每一个视图都接收你传递给它们的额外的参数时才有意义,不然其中一个以上视图不接收该参数都将致使错误异常。
可获取URL的主要信息负责处理他的视图的标识(例如名称),其余必须参与查找正确URL的信息,包括视图参数的类型(位置,关键字)和值
django提供了一种解决方案,使得URL映射器是URL设计的惟一存储库,用URLconf提供它,能够在两个方向上使用:
1.从用户/浏览器请求的URL开始,它调用正确的django视图,提供它可能须要的任何参数以及从URL中提取的值,
2.从相应的django视图的标识以及将传递给他的参数的值开始获取管理的URL
第二种就是所谓的URL方向解析,方向URL匹配,方向URL查找或者仅仅URL反转。
Django提供了用于执行URL反转的工具,以匹配须要URL的不一样层:
1.在模板中:使用URL模板标签。(也就是写前端网页时)
2.在python代码中:使用reverse()
函数。(也就是views中)
3.在更高层的与处理Django模型实例相关的代码中:使用get_absolute_url()
方法。(也就是在模型model中)
例子:URLconf
from django.urls import path from . import views urlpatterns = [ #... path('articles/<int:year>/', views.year_archive, name='news-year-archive'), #... ]
根据这个设计,对应与年份nnnn的档案URL是/articles/nnnn
您可使用下面的方式在模板中得到这些内容:
<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a> {# Or with the year in a template context variable: #} <ul> {% for yearvar in year_list %} <li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li> {% endfor %} </ul>
或者在python代码中:
from django.urls import reverse from django.http import HttpResponseRedirect def redirect_to_year(request): # ... year = 2006 # ... return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))
若是出于某种缘由决定应该更改每一年发布文章内容的URL,那么您只须要更改URLconf中的条目。
在某种状况下,视图是具备通用性的,所以URL和视图之间可能存在多对一的关系,对于这些状况,视图名称在倒转URL时不是一个足够好的标识符。见下面的命名URL模式
URL模式:
#mysite/urls.py from django.urls import include,path urlpatterns = [ path(r'blog/', include('app01.urls')), ] #app01/urls.py from django.urls import path from app01 import views urlpatterns = [ path('art/',views.art,name='app01-art'), ] #app01/views.py from django.shortcuts import render def art(request): return render(request,'art.html',{"day":"abc"}) #art.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>{{ day }}</h1> <a href="{% url 'app01-art' %}">点击</a> </body> </html>
视图:在视图函数中调用url,使用reverse('别名')
####urls from django.conf.urls import url,include from app01 import views urlpatterns = [ url(r'^art/', views.art3, name='app01-art'), ] ####views def art3(request): print(reverse('app01-art')) #在视图函数中对url进行反向解析 return HttpResponse("OK")
URL命名空间能够保证反查到惟一的URL,即便不一样的app使用相同的URL名称。
第三方应用始终使用带命名空间的URL是一个很好的作法。
相似地,它还容许你在一个应用有多个实例部署的状况下反查URL。 换句话讲,由于一个应用的多个实例共享相同的命名URL,命名空间提供了一种区分这些命名URL 的方法。
实现命名空间的作法很简单,在urlconf文件中添加app_name = 'polls'
和namespace='author-polls'
这种相似的定义
例子:
urls.py from django.urls import include, path urlpatterns = [ path('author-polls/', include('polls.urls', namespace='author-polls')), path('publisher-polls/', include('polls.urls', namespace='publisher-polls')), ]
polls/urls.py from django.urls import path from . import views app_name = 'polls' urlpatterns = [ path('', views.IndexView.as_view(), name='index'), path('<int:pk>/', views.DetailView.as_view(), name='detail'), ... ]
视图中的调用方法:
reverse('polls:index', current_app=self.request.resolver_match.namespace)
模板中:
{% url 'polls:index' %}