web框架django第二天
###URL配置 settings.py
* ROOT_URLCONF = 'mysite.urls'
###url转换(静态路由)
* from django.urls import path, re_path
* re_path(r'^add_book/$', views.add_book)
* 浏览器访问 http://127.0.0.1:8000/add_book/
* re_path(r'^book/add/$', views.add_book)
* 浏览器访问 http://127.0.0.1:8000/book/add/
* r'原生字符串'
* 不需要转义
* 建议都写上$符号
* 防止url匹配问题
* ^以什么开头,不需要添加/,系统会自动重定向
* settings.py 配置文件
* APPEND_SLASH = True # 默认
###动态路由(正则表达式)
* re_path(r'^blog/\d{4}/$', views.blog)
* 浏览器访问 http://127.0.0.1:8000/blog/1234/
###分组匹配
* re_path(r'^blog/(\d{4})/$', views.blog)
* views.py 按照位置参数传递给函数
```python
def blog(request, year):
print(year, type(year))
return HttpResponse('ok')
```
###分组命名匹配
* urls.py
```python
re_path(r'^blog/(?P<year>\d{4})/$', views.blog)
```
* views.py 按照关键字参数传递给函数
```python
def blog(request, year):
print(year, type(year))
return HttpResponse('ok')
```
###视图函数中指定默认值
* urls.py
```python
re_path(r'^blog/$', views.blog)
re_path(r'^blog/page(?P<num>\d+)/$', views.blog)
```
* views.py
```python
def blog(request, num='1'):
return HttpResponse('ok')
```
###include其他的URLconfs
* urls.py
```python
from django.urls import path, re_path, include
re_path(r'^app01/', include('app01.urls')),
```
* app01/urls.py
```python
re_path(r'^blog/$', views.blog)
```
* 浏览器访问 http://127.0.0.1:8000/app01/blog/
###使用最新版本的django2.2.3报错(使用HttpResponse时,添加encode('utf8'))
* 报错信息
```python
Traceback (most recent call last):
File "G:\python3.6\lib\socketserver.py", line 654, in process_request_thread
self.finish_request(request, client_address)
File "G:\python3.6\lib\socketserver.py", line 364, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "G:\python3.6\lib\socketserver.py", line 724, in __init__
self.handle()
File "G:\python3.6\lib\site-packages\django\core\servers\basehttp.py", line 171, in handle
self.handle_one_request()
File "G:\python3.6\lib\site-packages\django\core\servers\basehttp.py", line 194, in handle_one_request
handler.run(self.server.get_app())
File "G:\python3.6\lib\wsgiref\handlers.py", line 144, in run
self.close()
File "G:\python3.6\lib\site-packages\django\core\servers\basehttp.py", line 111, in close
super().close()
File "G:\python3.6\lib\wsgiref\simple_server.py", line 35, in close
self.status.split(' ',1)[0], self.bytes_sent
AttributeError: 'NoneType' object has no attribute 'split'
```
* return HttpResponse('ok'.encode('utf8')) # 就不会报错了
###传递额外的参数给视图函数
* urls.py
```python
re_path(r'^blog/(?P<year>\d{4})/$', views.blog, {'month': '12'})
```
* views.py
```python
def blog(request, *args, **kwargs):
print(args) # ()
print(kwargs) # {'year': '1234', 'month': '12'}
return HttpResponse('ok'.encode('utf8'))
```
* 浏览器访问 http://127.0.0.1:8000/blog/1234/
* 如果位置参数或关键字参数和后面额外传递的字典里的参数同名,则会被后面的字典里的参数替换
###URL命名和URL反向解析
* urls.py
```python
re_path(r'^book/add/$', views.add_book, name='add_book')
```
* 模板文件
```html
<a href="{% url 'add_book' %}">添加书名</a>
```
* views.py视图函数
```python
from django.shortcuts import render, redirect, HttpResponse, reverse
return redirect(reverse('app01:add_book'))
```
###URL命名和URL反向解析(分组)
* urls.py
```python
re_path(r'^blog/(\d{4})/$', views.blog, name='blog')
```
* 模板文件
```html
<a href="{% url 'blog' 2014 %}">添加书名</a>
```
* views.py视图函数
```python
from django.shortcuts import render, redirect, HttpResponse, reverse
return redirect(reverse('blog', args=('2019',)))
```
###URL命名和URL反向解析(分组命名)
* urls.py
```python
re_path(r'^blog/(?P<year>\d{4})/$', views.blog, name='blog')
```
* 模板文件
```html
<a href="{% url 'blog' year=2016 %}">添加书名</a>
```
* views.py视图函数
```python
from django.shortcuts import render, redirect, HttpResponse, reverse
return redirect(reverse('blog', kwargs={'year': '2019'}))
```
###命名空间模式
* urls.py
```python
re_path(r'^app01/', include('app01.urls', namespace='app01')),
re_path(r'^app02/', include('app02.urls', namespace='app02')),
```
* 报错
```python
Watching for file changes with StatReloader
Exception in thread django-main-thread:
Traceback (most recent call last):
File "G:\python3.6\lib\threading.py", line 916, in _bootstrap_inner
self.run()
File "G:\python3.6\lib\threading.py", line 864, in run
self._target(*self._args, **self._kwargs)
File "G:\python3.6\lib\site-packages\django\utils\autoreload.py", line 54, in wrapper
fn(*args, **kwargs)
File "G:\python3.6\lib\site-packages\django\core\management\commands\runserver.py", line 117, in inner_run
self.check(display_num_errors=True)
File "G:\python3.6\lib\site-packages\django\core\management\base.py", line 390, in check
include_deployment_checks=include_deployment_checks,
File "G:\python3.6\lib\site-packages\django\core\management\base.py", line 377, in _run_checks
return checks.run_checks(**kwargs)
File "G:\python3.6\lib\site-packages\django\core\checks\registry.py", line 72, in run_checks
new_errors = check(app_configs=app_configs)
File "G:\python3.6\lib\site-packages\django\core\checks\urls.py", line 40, in check_url_namespaces_unique
all_namespaces = _load_all_namespaces(resolver)
File "G:\python3.6\lib\site-packages\django\core\checks\urls.py", line 57, in _load_all_namespaces
url_patterns = getattr(resolver, 'url_patterns', [])
File "G:\python3.6\lib\site-packages\django\utils\functional.py", line 80, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "G:\python3.6\lib\site-packages\django\urls\resolvers.py", line 579, in url_patterns
patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
File "G:\python3.6\lib\site-packages\django\utils\functional.py", line 80, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "G:\python3.6\lib\site-packages\django\urls\resolvers.py", line 572, in urlconf_module
return import_module(self.urlconf_name)
File "G:\python3.6\lib\importlib\__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 994, in _gcd_import
File "<frozen importlib._bootstrap>", line 971, in _find_and_load
File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 678, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "G:\2019老男孩周末26期\day15\课下练习\mysite_day15\mysite_day15\urls.py", line 22, in <module>
re_path(r'^app01/', include('app01.urls', namespace='app01')),
File "G:\python3.6\lib\site-packages\django\urls\conf.py", line 39, in include
'Specifying a namespace in include() without providing an app_name '
django.core.exceptions.ImproperlyConfigured: Specifying a namespace in include() without providing an app_name is not supported. Set the app_name attribute in the included module, or pass a 2-tuple containing the list of patterns and app_name instead.
```
* 解决方法 urls.py
```python
from django.urls import path, re_path, include
re_path(r'^app01/', include(('app01.urls', 'app01'), namespace='app01')),
re_path(r'^app02/', include(('app02.urls', 'app02'), namespace='app02')),
```
* app01/urls.py
```python
from django.urls import path, re_path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
re_path(r'^home/$', views.home, name='home'),
]
```
* app02/urls.py
```python
from django.urls import path, re_path
from app02 import views
urlpatterns = [
path('admin/', admin.site.urls),
re_path(r'^home/$', views.home, name='home'),
]
```
* app01/views.py
```python
def home(request):
return render(request, 'app01home.html')
```
* app02/views.py
```python
def home(request):
return render(request, 'app02home.html')
```
* app01home.html
```html
<a href="{% url 'app01:home' %}">app01家目录</a>
<a href="{% url 'app02:home' %}">app02家目录</a>
```
-----------------------------------------------------------------------------------
###返回当前日期和时间的视图
```python
import datetime
def current_datetime(request):
current_time = datetime.datetime.now()
return HttpResponse('<html><body>current time: %s</body></html>' % current_time)
```
###FBV基于函数的视图(Function Base View)
* mysite/urls.py 开始路由文件
```python
from django.urls import path, re_path, include
urlpatterns = [
path('admin/', admin.site.urls),
re_path(r'^app02/', include(('app02.urls', 'app02'), namespace='app02')),
]
```
* app02/urls.py 命名空间app02路由文件
```python
from app02 import viewsre_path(r'^class/add/$', views.add_class, name='add_class'),
```
* app02/views.py 视图文件
```python
from django.shortcuts import render, HttpResponse, redirect, reverse
def add_class(request):
if request.method == "POST":
# 接收请求参数,添加到数据库
return redirect(reverse('app01:home'))
return render(request, 'add_class.html')
```
###CBV基于类的视图(Class Base View)
* mysite/urls.py 开始路由文件
```python
from django.urls import path, re_path, include
urlpatterns = [
path('admin/', admin.site.urls),
re_path(r'^app01/', include(('app01.urls', 'app01'), namespace='app01')),
]
```
* app01/urls.py 命名空间app01路由文件
```python
urlpatterns = [
path('admin/', admin.site.urls),
re_path(r'^class/add/$', views.AddClasses.as_view(), name='add_class'),
]
```
* app01/views.py 视图文件
```python
from django.shortcuts import render, redirect, HttpResponse, reverse
from django.views import View
class AddClasses(View):
def get(self, request):
return render(request, 'add_class.html')
def post(self, request):
# 接收请求参数,添加到数据库
return redirect(reverse('app01:home'))
```
###给视图加装饰器
* 使用装饰器装饰FBV app02/views.py
```python
from django.shortcuts import render, HttpResponse, redirect, reverse
import time
def wrapper(func):
def inner(*args, **kwargs):
start_time = time.time()
# 执行被装饰函数前增加的逻辑
ret = func(*args, **kwargs)
# 执行被装饰函数后增加的逻辑
print('used: %s' % (time.time() - start_time))
return ret
return inner
@wrapper
def add_class(request):
if request.method == "POST":
# 接收请求参数,添加到数据库
return redirect(reverse('app02:home'))
return render(request, 'add_class.html')
```
* 使用装饰器装饰CBV app01/views.py 方法一(分别加在每个请求方法上)
```python
from django.shortcuts import render, redirect, HttpResponse, reverse
from django.utils.decorators import method_decorator
from django.views import View
import time
def wrapper(func):
def inner(*args, **kwargs):
start_time = time.time()
# 执行被装饰函数前增加的逻辑
ret = func(*args, **kwargs)
# 执行被装饰函数后增加的逻辑
print('used: %s' % (time.time() - start_time))
return ret
return inner
class AddClasses(View):
@method_decorator(wrapper)
def get(self, request):
return render(request, 'add_class.html')
@method_decorator(wrapper)
def post(self, request):
# 接收请求参数,添加到数据库
return redirect(reverse('app01:home'))
```
* 使用装饰器装饰CBV app01/views.py 方法二(加在dispatch方法上)
```python
from django.shortcuts import render, redirect, HttpResponse, reverse
from django.utils.decorators import method_decorator
from django.views import View
import time
def wrapper(func):
def inner(*args, **kwargs):
start_time = time.time()
# 执行被装饰函数前增加的逻辑
ret = func(*args, **kwargs)
# 执行被装饰函数后增加的逻辑
print('used: %s' % (time.time() - start_time))
return ret
return inner
class AddClasses(View):
@method_decorator(wrapper)
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
def get(self, request):
return render(request, 'add_class.html')
def post(self, request):
# 接收请求参数,添加到数据库
return redirect(reverse('app01:home'))
```
* 使用装饰器装饰CBV app01/views.py 方法三(加在类上[请求方法])
```python
from django.shortcuts import render, redirect, HttpResponse, reverse
from django.utils.decorators import method_decorator
from django.views import View
import time
def wrapper(func):
def inner(*args, **kwargs):
start_time = time.time()
# 执行被装饰函数前增加的逻辑
ret = func(*args, **kwargs)
# 执行被装饰函数后增加的逻辑
print('used: %s' % (time.time() - start_time))
return ret
return inner
@method_decorator(wrapper, name='post')
@method_decorator(wrapper, name='get')
class AddClasses(View):
def get(self, request):
return render(request, 'add_class.html')
def post(self, request):
# 接收请求参数,添加到数据库
return redirect(reverse('app01:home'))
```
* 使用装饰器装饰CBV app01/views.py 方法二(加在dispatch方法上)
```python
from django.shortcuts import render, redirect, HttpResponse, reverse
from django.utils.decorators import method_decorator
from django.views import View
import time
def wrapper(func):
def inner(*args, **kwargs):
start_time = time.time()
# 执行被装饰函数前增加的逻辑
ret = func(*args, **kwargs)
# 执行被装饰函数后增加的逻辑
print('used: %s' % (time.time() - start_time))
return ret
return inner
class AddClasses(View):
@method_decorator(wrapper)
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
def get(self, request):
return render(request, 'add_class.html')
def post(self, request):
# 接收请求参数,添加到数据库
return redirect(reverse('app01:home'))
```
* 使用装饰器装饰CBV app01/views.py 方法四(加在类上[dispatch方法])
```python
from django.shortcuts import render, redirect, HttpResponse, reverse
from django.utils.decorators import method_decorator
from django.views import View
import time
def wrapper(func):
def inner(*args, **kwargs):
start_time = time.time()
# 执行被装饰函数前增加的逻辑
ret = func(*args, **kwargs)
# 执行被装饰函数后增加的逻辑
print('used: %s' % (time.time() - start_time))
return ret
return inner
@method_decorator(wrapper, name='dispatch')
class AddClasses(View):
def get(self, request):
return render(request, 'add_class.html')
def post(self, request):
# 接收请求参数,添加到数据库
return redirect(reverse('app01:home'))
```
###框架
* MVC框架(Model模型 View视图 Controller控制器)
* 耦合性低,重用性高,生命周期成本低等优点,重视结果
* MTV框架(Model模型 Template模板 View视图)
* 重视过程
* ORM对象关系映射(Object Relational Mapping)
###request对象
* app02/views.py
```python
from django.shortcuts import render, HttpResponse, redirect, reverse
import datetime
def current_datetime(request):
print("path_info:", request.path_info) # /app02/now/ 返回用户访问url,不包括域名
print("method:", request.method) # GET
print("POST:", request.POST) # <QueryDict: {}>
print("GET:", request.GET) # <QueryDict: {}>
print("body:", request.body) # b''
print("scheme:", request.scheme) # http或https
print("path:", request.path) # 同path_info
print("session:", request.session)
print("COOKIES:", request.COOKIES)
print("FILES:", request.FILES) # 文件
print("META:", request.META) # 请求头
print("get_host:", request.get_host())
print("get_full_path:", request.get_full_path())
print("is_ajax:", request.is_ajax())
current_time = datetime.datetime.now()
return HttpResponse('<html><body>current time: %s</body></html>' % current_time)
```
###JsonResponse对象
```python
from django.http import JsonResponse
def func(request):
dit = {"name": "lily"}
return JsonResponse(dit) # Content-Type: application/json
```
* 对比json序列化
```python
import json
def func(request):
dit = {"name": "lily"}
return HttpResponse(json.dumps(dit)) # Content-Type: text/html; charset=utf-8
```
* 通过修改响应值,返回json对象
```python
import json
def func(request):
dit = {"name": "lily"}
res = HttpResponse(json.dumps(dit))
res['Content-Type'] = 'application/json'
return res # Content-Type: application/json
```
* 指定响应内容类型
```python
import json
def func(request):
dit = {"name": "lily"}
res = HttpResponse(json.dumps(dit), content_type='application/json')
return res # Content-Type: application/json
```
* In order to allow non-dict objects to be serialized set the safe parameter to False.
* 为了允许非字典对象序列号设置safe参数为False
```python
from django.http import JsonResponse
def func(request):
return JsonResponse(['a', 8, 'z'], safe=False) # Content-Type: application/json
```
---------------------------------------------------------------------------
###模板常用语法
* {{ 变量 }}
* .索引
* .key
* .属性
* .方法
* views.py
```python
def template_test(request):
lst = ['abc', '123', 'xyz']
dit = {'name': 'lily', 'age': 18}
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def eating(self):
return '%s is eating.' % self.name
Zhangsan = Person('zhangsan', 20)
Lisi = Person('lisi', 21)
WangWu = Person('wangwu', 22)
person_lst = [Zhangsan, Lisi, WangWu]
return render(request, 'template_test.html', {'lst': lst, 'dit': dit, 'person_lst': person_lst,
'file': 100 * 1024 * 1024, 'value': 4, 'v1': '这是什么鬼,到底什么情况啊?',
'v2': datetime.datetime.now(),
'atag': '<a href="http://www.baidu.com">百度</a>'})
```
* template_test.html
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板测试</title>
</head>
<body>
列表:{{ lst }}
<br>
字典:{{ dit }}
<br>
对象列表:{{ person_lst }}
<br>
<br>
列表中的第一个元素:{{ lst.0 }}
<br>
列表中的第二个元素:{{ lst.1 }}
<br>
列表中的第三个元素:{{ lst.2 }}
<br>
<br>
字典的name值:{{ dit.name }}
<br>
字典的age值:{{ dit.age }}
<br>
字典的所有键值:{{ dit.keys }}
<br>
字典的所有元素:{{ dit.items }}
<br>
<br>
对象列表的第一个对象:{{ person_lst.0 }}
<br>
对象列表的第二个对象:{{ person_lst.1 }}
<br>
对象列表的第三个对象:{{ person_lst.2 }}
<br>
<br>
对象列表的第一个对象的name属性值:{{ person_lst.0.name }}
<br>
对象列表的第一个对象的age属性值:{{ person_lst.0.age }}
<br>
对象列表的第一个对象的eating方法:{{ person_lst.0.eating }}
<br>
<br>
过滤器default: {{ aaa|default:"不存在或为空" }}
<br>
filesizeformat: {{ file|filesizeformat }}
<br>
add: {{ value|add:"2" }}
<br>
add: {{ value|add:"a" }}
<br>
add: {{ value|add:"2abc" }}
<br>
add: {{ lst|add:person_lst }}
<br>
upper: {{ lst.0|upper }}
<br>
lower: {{ lst.0|lower }}
<br>
title: {{ lst.0|title }}
<br>
length: {{ lst.0|length }}
<br>
ljust: {{ lst.0|ljust:"10" }}
<br>
rjust: {{ lst.0|rjust:"10" }}
<br>
center: {{ lst.0|center:"15" }}
<br>
first: {{ lst.0|first }}
<br>
last: {{ lst.0|last }}
<br>
slice: {{ lst|slice:"1:-1" }}
<br>
join: {{ lst|join:"-" }}
<br>
join: {{ lst.0|join:"-" }}
<br>
truncatechars: {{ v1|truncatechars:6 }}
<br>
date: {{ v2|date:"Y-m-d H:i:s" }}
<br>
默认:{{ atag }}
<br>
safe: {{ atag|safe }}
</body>
</html>
```
* 浏览器访问效果
```html
列表:['abc', '123', 'xyz']
字典:{'name': 'lily', 'age': 18}
对象列表:[<app02.views.template_test.<locals>.Person object at 0x00000000047045C0>, <app02.views.template_test.<locals>.Person object at 0x0000000004704400>, <app02.views.template_test.<locals>.Person object at 0x000000000478FC18>]
列表中的第一个元素:abc
列表中的第二个元素:123
列表中的第三个元素:xyz
字典的name值:lily
字典的age值:18
字典的所有键值:dict_keys(['name', 'age'])
字典的所有元素:dict_items([('name', 'lily'), ('age', 18)])
对象列表的第一个对象:<app02.views.template_test.<locals>.Person object at 0x00000000047045C0>
对象列表的第二个对象:<app02.views.template_test.<locals>.Person object at 0x0000000004704400>
对象列表的第三个对象:<app02.views.template_test.<locals>.Person object at 0x000000000478FC18>
对象列表的第一个对象的name属性值:zhangsan
对象列表的第一个对象的age属性值:20
对象列表的第一个对象的eating方法:zhangsan is eating.
过滤器default: 不存在或为空
filesizeformat: 100.0 MB
add: 6
add:
add:
add: ['abc', '123', 'xyz', <app02.views.template_test.<locals>.Person object at 0x00000000047045C0>, <app02.views.template_test.<locals>.Person object at 0x0000000004704400>, <app02.views.template_test.<locals>.Person object at 0x000000000478FC18>]
upper: ABC
lower: abc
title: Abc
length: 3
ljust: abc
rjust: abc
center: abc
first: a
last: c
slice: ['123']
join: abc-123-xyz
join: a-b-c
truncatechars: 这是什么鬼…
date: 2019-07-22 21:42:33
默认:<a href="http://www.baidu.com">百度</a>
safe: 百度
```
* 当模板系统遇到一个(.)时,会按照如下的顺序去查询:
* 在字典中查询
* 属性或者方法
* 数字索引
* Tags{% %} 逻辑相关操作
* for循环
```html
<table border="1">
<tr>
<th>forloop.counter</th>
<th>forloop.counter0</th>
<th>forloop.revcounter</th>
<th>forloop.revcounter0</th>
<th>forloop.first</th>
<th>forloop.last</th>
<th>p_obj.name</th>
<th>p_obj.age</th>
</tr>
{% for p_obj in person_lst %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ forloop.counter0 }}</td>
<td>{{ forloop.revcounter }}</td>
<td>{{ forloop.revcounter0 }}</td>
<td>{{ forloop.first }}</td>
<td>{{ forloop.last }}</td>
<td>{{ p_obj.name }}</td>
<td>{{ p_obj.age }}</td>
</tr>
{% endfor %}
{% for p_obj in person_lst0 %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ forloop.counter0 }}</td>
<td>{{ forloop.revcounter }}</td>
<td>{{ forloop.revcounter0 }}</td>
<td>{{ forloop.first }}</td>
<td>{{ forloop.last }}</td>
<td>{{ p_obj.name }}</td>
<td>{{ p_obj.age }}</td>
</tr>
{% empty %}
<tr>
<td colspan="8">空了</td>
</tr>
{% endfor %}
</table>
```
* if判断
```html
{% if person_lst.0.age > 40 %}
40岁以上
{% elif person_lst.0.age > 30 %}
30岁以上
{% elif person_lst.0.age > 20 %}
20岁以上
{% else %}
20岁以下
{% endif %}
```
* with
```html
{% with person_lst.0 as zhangsan %}
zhangsan.name = {{ zhangsan.name }}
<br>
zhangsan.age = {{ zhangsan.age }}
{% endwith %}
```
* csrf_token csrf跨站请求伪造(Cross Site Request Forgery) token令牌
* 这个标签用于跨站请求伪造保护。
* 在页面的form表单里面写上{% csrf_token %}
老师博客地址: https://www.cnblogs.com/maple-shaw/articles/9282718.html
https://www.cnblogs.com/maple-shaw/articles/9285269.html
https://www.cnblogs.com/maple-shaw/articles/9333821.html