Python 的 web 框架有 Django、Tornado、Flask 等多种,Django 相较于其他 web 框架其优势为:大而全,框架本身集成了ORM、模型绑定、模板引擎、缓存、Session 等诸多功能。
一、基本配置
1、创建 django 程序
- 通过终端命令来创建
2、程序目录
3、配置文件
3.1 数据库
django 默认配置数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
以下将 django 数据库修改为 mysql
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME':'dbname',
'USER': 'root',
'PASSWORD': 'xxx',
'HOST': 'localhost', # 连接本地的数据库,也可以不写,默认是本地
'PORT': 3306,
}
}
由于 Django 内部连接 Mysql 时使用的是Mysqldb 模块,而 Python3 中还没有这个模块,所以需要使用pymysql 来代替
如下设置放置的与 project 同名的配置的 __init__.py 文件中
import pymysql
pymysql.install_as_MySQLdb()
3.2 模板
TEMPLATE_DIRS = ( os.path.join(BASE_DIR,'templates'), )
3.3 静态文件
STATICFILES_DIRS = ( os.path.join(BASE_DIR,'static'), )
3.4 新增APP
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01', 'app02', ]
二、Django 框架介绍
Django 框架简介
MVC 框架和MTV框架0(了解即可)
MVC,全名是Model View Controller,是软件工程中的一种软件架构模式,把软件系统分为三个基础部分:模型(Model)、视图(View)和控制器(Controller),具有耦合性低、重用性高、生命周期成本低等优点。
想要更详细的了解MVC模式?>>>>点我
Django 框架的不同之处在于它拆分的三部分为:Model(模型)、Template(模板)和View(视图),也就是MTV框架。
1、Django 的 MTV 模式
Model(模型):负责业务对象与数据库的对象(ORM)
Template(模板):负责如何把页面展示给用户
View(视图):负责业务逻辑,并在适当的时候调用 Model 和 Template
此外,Django 还有一个 urls 分发器,它的作用是将一个个的 URL 页面请求分发给不同的 View 处理,View 再调用相应的 Model 和Template
2、Django 框架图示
APP
一个Django 项目可以分为很多个APP,用来隔离不同功能模块的代码
1、命令行创建
python manage.py startapp app01
2、使用 pycharm 创建
在下方弹出的命令窗口输入:
startapp app01 # 其中app01只是给创建的app取的名字,可以是其他的例如:login等名字
三、路由系统
URL配置(URLconf)就像 Django 所支撑网站的目录。它的本质是URL 与要为该 URL 调用的视图函数之间的映射表;
你就是以这种方式告诉 Django,对于这个 URL 调用这段代码,对于那个 URL 调用哪段代码。
URLconf 配置
1、基本格式:
from django.conf.urls import url urlpatterns = [ url (正则表达式, view视图函数, 参数别名), ] 参数说明: 1、正则表达式:一个正则表达式字符串 2、views视图函数:一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串 3、参数:可选的要传递给视图函数的默认参数(字典的形式) 4、别名:一个可选的 name 参数
注意:在Django 2.0 版本中的路由系统已经替换成下面的写法了(官方文档):
from django.urls import path urlpatterns = [ path('articles/2003/', views.special_case_2003), path('artices/<int:year>/', views.year_archive), path('artices/<int:year>/<int:month>/', views.month_archive), path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail ), ]
正则表达式详解
1、基本配置
from django.conf.urls import url from . import views urlpatterns = [ url(r'^articles/2003/$', views.special_case_2003), url(r'^articles/([0-9]{4})/$', views.year_archive), 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), ]
注意事项:
1、urlpatterns 中元素按照书写顺序从上往下逐一匹配正则表达式,一旦匹配成功则不再继续。
2、若要从URL 中捕获一个值,只需要在它周围放置一对圆括号(分组匹配)。
3、不需要添加一个前导的反斜杠,因为每个URL都有。例如:应该是 ^articles 而不是 ^/articles。
4、每个正则表达式前面的 “r” 是可选的,但是建议加上。
2、补充说明
# 是否开启 URL 访问地址后面不为/ 跳转至带有 / 的路径的配置项 APPEND_SLASH = True
Django setting.py 配置文件中默认没有 APPEND_SLASH 这个参数,但Django 默认这个参数为 APPEND_SLASH = True。其作用就是自动在网址的结尾加上 “/”。
其结果就是:
我们定义了urls.py:
from django.conf.urls import url from app01 import views urlpatterns = [ url(r"^blog/$", views.blog), ]
访问 http://www.example.com/blog 时,默认将网址自动转换成 http://www/example/com/blog/。
如果在 setting,py 中设置了 APPEND_SLASH = False,此时我们再请求http://www.example.com/blog 时由于不会在后面自动添加一个/ 则不符合正则表达式,就会提示找不到页面。
分组命名匹配
上面的示例使用简单的正则表达式分组匹配(通过圆括号)来捕获URL中的值并以位置参数形式传递给视图。
在更高级的使用法中,可以使用分组命名匹配的正则表达式组来捕获URL中的值并以关键字参数形式传递给视图。
在Python 的正则表达式中,分组命名正则表达式组的语法是 (?P<name>pattern),注意:P是大写 其中 name 是组的名称,pattern是要匹配的模式。
下面是以上 URLconf 使用命名组的重写:
from django.conf.urls import url from . import views urlpatterns = [ url(r'^articles/2003/$', views.special_case_2003), url(r'^artical/(?P<year>[0-9]{4})/$',views.year_archive), url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$',views.month_archive), url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
这个示例和前面的示例完全相同,只有一个细微的差别:捕获的值作为关键字参数而不是位置参数传递给视图函数。
例如:针对 url /articles/2017/12/ 相当于按以下方式调用视图函数:
views.month_archive(request, year= "2017", month="12")
在实际应用中,使用分组命名匹配的方式可以让你的 URLconf 更加明晰且不容易产生参数顺序问题的错误,但是有些开发人员则认为分组命名组语法太丑陋、繁琐。
1、URLconf 匹配的位置
URLconf 在请求的 URL 上查找,将它当作一个普通的 Python 字符串。不包括 GET 和 POST 参数以及域名。
例如:http://www.example.com/myapp/ 请求中,URLconf 将查找myapp/。
在 http://www.example.com/myapp/?page=3 请求中,URLconf 仍将查找myapp/。
URLconf 不检查请求的方法。换句话说,所有的请求方法——同一个 URL 的 POST、GET、HEAD 等都将路由到相同的函数。
2、捕获的参数永远是字符串
每个在 URLconf 中捕获的参数都是作为一个普通的 Python 字符串传递给视图,无论正则表达式使用的是什么匹配方式。例如下面的这行 URLconf 中:
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
其中传递到函数 views.year_archive() 中的 year 参数永远是一个字符串类型。
3、视图函数中指定默认值
# urls.py 中 from django.conf.urls import url from . import views urlpatterns = [ url(r'^blog/$', views.page), url(r'^blog/page(?P<num>[0-9]+)/$', views.page), ] # views.py 中,可以为num 指定默认值 def page(request, num = '1'): pass
4、include 其他的 URLconfs
#At any point, your urlpatterns can “include” other URLconf modules. This #essentially “roots” a set of URLs below other ones. #For example, here’s an excerpt of the URLconf for the Django website itself. #It includes a number of other URLconfs: from django.conf.urls import include, url urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^blog/', include('blog.urls')), # 可以包含其他的URLconfs文件 ]
传递额外的参数给视图函数(了解)
URLconfs 具有一个钩子,让你传递一个 Python 字典作为额外的参数传递给视图函数。
django.conf.urls.url() 函数可以接收一个可选的第三个参数,它是一个字典,表示想要传递给视图函数的额外关键字参数。
例如:
from django.conf.urls import url from . import views urlpatterns = [ url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}), ]
在这个例子中,对于 /blog/2005/ 请求,Django 将调用views.year_archive(request, year="2005", foo="bar")。
这个技术在Syndication 框架中使用,来传递元数据和选项给视图。
命名URL和URL反向解析
在使用Django 项目时,一个常见的需求是获得URL的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的 URL等)或者用于处理服务器端的导航(重定向等)。
人们强烈希望不要硬编码这些 URL(费力、不可扩展且容易产生错误)或者设计一种与 URLconf 毫不相关的专门的 URL 生成机制,因为这样容易导致一定程度上产生过期的 URL。
换句话讲,需要的是一个DRY机制。除了其他点,它还允许设计的URL可以自动更新而不用遍历项目的源代码来搜索并替换过期的URL。
获取一个URL最开始想到的信息是处理它的视图的标识(例如名字),查找正确的URL的其它必要的信息有视图参数的类型(位置参数、关键字参数)和值。
Django提供一个方法是让 URL 进行映射,这是URL设计唯一的地方。你填充你的URLconf,然后可以双向使用它:
- 根据用户/浏览器发起的URL请求,它调用正确的Django视图,并从 URL 中提取它的参数需要的值。
- 根据Django视图的标识和将要传递给它的参数的值,获取与之关联的 URL。
第一方式是外面在前面的章节中一直讨论的方法。第二种方式叫做反向解析 URL、反向 URL匹配、反向 URL查询或者简单的URL反查。
在需要URL的地方,对于不同层级,Django提供不同的工具用于 URL反查:
- 在模板中:使用URL模板标签
- 在Python代码中:使用django.core.urlresolvers.reverse() 函数。
- 在更高层的与处理Django模型实例相关的代码中:使用get_absolute_url() 方法。
简单的说就是可以给我们的 URL 匹配规则起个别名,一个 URL 匹配模式起一个名字。这样以后就不需要写死 URL代码了,只需要通过名字来调用当前的 URL。
举例:
url(r'^home', views.home, name='home'), # 给我的url匹配模式起名为 home url(r'^index/(d*)', views.index, name='index'), # 给我的url匹配模式起名为index # 给 URL 起别名的话之后不管前面的views.index 或 views.home 怎样改变,在后面模板中都使用的是name的值,不会有任何影响
这样模板里面可以这样引用:
{% url "home" %} {% url "index" %}
在views函数中可以这样引用:
from django.urls import reverse reverse("index") # 在urls.py 文件中如果是 url(r'^index/(d*)', views.index, name='index', {'key': 'value'}), 的时候写成 reverse("index", args=(2018,))
例子:
考虑下面的 URLconf:
from django.conf.urls import url from . import views urlpatterns = [ # ... url(r'^articles/([0-9]{4})/$', views.year_archive, name = 'news-year-archive'), # ... ]
根据这里的设计,某一年nnnn对应的归档的URL是 /articles/nnnn/。
可以在模板的代码中使用下面的方法获得它们:
<a href="{% url 'news-year-archive' 2012 %}">2012 Achive</a> <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.shortcuts import redirect def redirect_to_year(request): # ... year = 2017 # ... return redirect(reverse('news-year-archive', args=(years, )))
如果出于某种原因决定要按年归档文章,发布的URL就应该调整一下,那么就只需要修改 URLconf 中的内容。
在某些场景中,一个视图是通用的,所以在 URL和视图之间存在多对一的关系。对于这些情况,当反查 URL时,只有视图的名字还不够。
注意:
为了完成上面例子中的 URL 反查,你将需要使用命名的URL模式。URL的名称使用的字符串可以包含任何你喜欢的字符。不只限制在合法的Python名称。
当命名你的 URL 模式时,请确保使用的名称不会与其它应用中的名称冲突。如果你的 URL 模式叫做 comment,而另外一个应用中也有一个同样的名称,当你在模板中使用这个名称的时候不能保证将插入哪个 URL。
在URL名称中加上一个前缀,比如应用的名称,将减少冲突的可能。我们建议使用 myapp-comment 而不是 comment
1、单一路由对应
url(r'^index$', views.index),
2、基于正则的路由
# $ url(r'^index/(d{4})$',views.index) #无命名分组 url(r'^index/(d{4})/(d{2})',views.index) #有命名分组 url(r'^index/(?P<year>d{4})/(?P<month>d{2})',views.index)
有无命名分组演示
############################无命名 #相当于传参数 url(r'^index/(d{4})',views.index) def index(request,arg): return HttpResponse(arg) #url访问http://127.0.0.1:8000/index/1113 #接受两个参数 url(r'^index/(d{4})/(d{2})',views.index) def index(request,arg,arg1): return HttpResponse("year: %s month: %s"%(arg,arg1)) #url访问http://127.0.0.1:8000/index/2017/06 year: 2017 month: 06 ############################有命名 url(r'^index/(?P<year>d{4})/(?P<month>d{2})',views.index) def index(request,year,month): return HttpResponse("year: %s month: %s"%(year,month)) #url访问http://127.0.0.1:8000/index/2017/06 year: 2017 month: 06
3、添加额外的参数
url(r'^manage/(?P<name>w*)', views.manage,{'id':333}),
4、为路由映射设置名称及使用
#应用一: url(r'^index',views.index,name="arg") {{ url "arg" }} 匹配index {{ url "arg" i}} #应用二: reverse反向获取url ##############根据url反生成名字 from django.shortcuts import reverse url(r'^index',views.index,name="arg") def index(request): v = reverse("arg") print(v) return HttpResponse() #用户访问http://127.0.0.1:8000/index /index ##############根据url改变url url(r'^index/(d+)/',views.index,name="n1") def index(request,xx): v = reverse('n1',args=(1,)) print(v) return HttpResponse("...") #访问http://127.0.0.1:8000/index/222/ /index/1/
url(r'^home', views.home, name='h1'), url(r'^index/(d*)', views.index, name='h2'),
设置名称之后,可以在不同的地方调用,如:
- 模板中使用生成URL {% url "h2" 2012 %}
- 函数中使用生成URL reverse("h2", args = (2012,)) 路径: django.url.reverse
- Model 中使用获取URL 自定义 get_absolute_url() 方法
class NewType(models.Model): caption = models.CharField(max_length=16) def get_absolute_url(self): """ 为每个对象生成一个URL 应用:在对象列表中生成查看详细的URL,使用此方法即可!!! :return: """ # return '/%s/%s' % (self._meta.db_table, self.id) # 或 from django.urls import reverse return reverse('NewType.Detail', kwargs={'nid': self.id})
获取请求配置成功的URL信息:request.resolver_match
5、根据app 对路由规则进行分发
url(r'^app01/',include("app01.urls")) url(r'^app02/',include("app02.urls")) #没有匹配成功,返回默认页面 url(r'^',include("views.default"))
6、命名空间
6.1 project.urls.py
from django.conf.urls import url, include urlpatterns = [ url(r'^a/', include('app01.urls', namespace='author-polls')), url(r'^b/', include('app01.urls', namespace='publisher-polls')), ]
6.2 app01.urls.py
from django.conf.urls import url from app01 import views app_name='app01' urlpatterns = [ url(r'^(?P<pk>d)/$', views.detail, name = 'detail'), ]
6.3 模板中的引用:
{% url 'app01:detail' pk=12 pp=99 %}
6.4 views 中的函数引用:
v = reverse('app01:detail', kwargs={'pk': 11})