Python学习笔记Day19 - Django进阶

路由系统URL

a. url路由(旧版)

  • 单个参数(\d+)

    url(r'^detail-(\d+).html', views.detail)

  • 多个参数按顺序赋给形参

    url(r'^detail-(\d+)-(\d+).html', views.detail)
    def func(request, *args, **kwargs):
    args = (2,9)

  • 多个参数指定形参 (最常用)

    url(r'^detail-(?P\d+)-(?P\d+).html', views.detail)

    def func(request, *args, **kwargs):
    kwargs =

新版使用path代替

a. path路由

  • path参数

    path('detail/int:p/', views.detail),
    path('articles/2003/', views.special_case_2003),
    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),

    def func(request, *args, **kwargs):
    kwargs = {'year': 1, 'month': 3}
    # 参数
    int -> 匹配0和正整数
    str -> 匹配任何非空字符串但不包括/,不写默认匹配str
    slug -> 可理解为注释,匹配任何ascii码,包括连字符-和下划线_
    uuid -> 匹配一个uuid对象(该对象必须包括破折号—,所有字母必须小写)
    path -> 匹配所有的字符串 包括/(意思就是path前边和后边的所有)

    path里不再需要用r,^,$符号
    默认采用截止符方式,需要后加参数用?

  • re_path()

    (?P<var>...) ...中直接写re规则

    re_path(r'^articles/(?P[0-9]{4})/$', views.year_archive),
    re_path(r'^articles/(?P[0-9]{4})/(?P[0-9]{2})/$', views.month_archive),
    re_path(r'^articles/(?P[0-9]{4})/(?P[0-9]{2})/(?P[\w-]+)/$', views.article_detail),

    两种嵌套参数

    re_path(r'^blog/(page-(\d+)/)?$', blog_articles),
    re_path(r'^comments/(?:page-(?P<page_number>\d+)/)?$', comments), # 推荐

    (?:...)为非捕获参数

b. name命名

对URL进行命名,方便更改、调用和reverse (以后可以根据此名称生成自己想要的URL)

  • url里指定name

    path('asdfasdfasdf/', views.index, name='i1'),
    path('yug/(\d+)/(\d+)/', views.index, name='i2'),
    path('buy/int:pid/int:nid/', views.index, name='i3'),

  • html里通过name生成url跳转

    ./xxx.html
    action="{% url "i1" %}" # asdfasdfasdf/
    action="{% url "i2" 1 2 %}" # yug/1/2/
    action="{% url "i3" pid=1 nid=9 %}" # buy/1/9/
    {{request.path_info}} # 跳转到当前的URL

  • 反转name生成url

    ./views.py
    def func(request, *args, **kwargs):
    from django.urls import reverse
    url1 = reverse('i1') # asdfasdfasdf/
    url2 = reverse('i2', args=(1,2,)) # yug/1/2/
    url3 = reverse('i3', kwargs={'pid': 1, "nid": 9}) # buy/1/9/

c. 多级路由分发

  • 分发至app

    ./project/urls.py
    from django.conf.urls import url,include
    urlpatterns = [
    path('cmdb/', include("app01.urls")),
    path('monitor/', include("app02.urls")),
    ]

    ./app01/urls.py
    from app01 import views
    urlpatterns = [
    path('login/', views.login),
    ]

    ./app02/urls.py
    from app02 import views
    urlpatterns = [
    path('login/', views.login),
    ]

    被包含的URLconf 会收到来自父URLconf 捕获的任何参数

    path('/blog/', include('foo.urls.blog')),

  • 同名前缀分组

    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)),
    ]

d. 命名空间

./project/urls.py
path('admin/', include('app01.urls',namespace='m1'))
path('crm/', include('app02.urls',namespace='m2'))

./app01.urls
app_name = 'n1'

./views.py
reverse('m1:n1', kwargs={'key': 'value'})

命名空间可以组合嵌套

e. 默认值

urlpatterns = [
path('blog/', views.page), # 不指定num参数时,默认num=1
path('blog/pageint:num/', views.page),
]

def page(request, num=1):
...

f. 添加额外参数给views (钩子)

path('index/', views.index, {'name': 'alex'}), # 传入额外值name = 'alex'

def index(request,name):
print(name)
return HttpResponse('OK')

path('blog/', include('inner'), {'blog_id': 3}), # 为include的所有url传递额外值

模板文件分路由配置

'DIRS': [os.path.join(BASE_DIR, 'templates')] 是指到 BASE_DIR/templates文件夹中去取模板
'DIRS': [os.path.join(BASE_DIR, 'app1/templates')] 是指导 BASE_DIR/app1/templates文件夹中去取模板

一般来说,应该设置'DIRS': [os.path.join(BASE_DIR, 'templates')],公用的templates需要指定。
app1专用的templates,放在app1/templates下,可以不需指定。
因为在app1.views中若要指定一个专用模板,只要直接写‘app1_index.html’,Django服务器会在views文件所在的当前层(/app1)中找到templates,从而找到模板'app1_index.html'.

指定公用的templates路径,所有apps都可以调用,方便快捷。
app专用的templates不需要指定,这样当要复用这个app的时候,不需要考虑templates路径问题。

视图views.py

a. 获取用户请求数据

request.GET
request.POST
request.FILES
request.path_info # 当前URL
request.XXX

- request.body # 用户数据放在请求body里打包发送
request.GET.get()
request.POST
request.FILES

- request.Meta(...)
request.method
request.path_info
request.COOKIES
request....

- request.method(PUT,DELETE)
request.GET/POST会将请求body打包,其他不会
取body用request.body

- 请求的其他信息
from django.core.handlers.wsgi import WSGIRequest
request.environ
request.environ['HTTP_USER_AGENT']

b. checkbox等多选的内容

request.POST.getlist()

c. 上传文件

上传文件时,form标签要做特殊设置

<form ... enctype="multipart/form-data">

request.POST.get('1.jpg') # 获取上传文件的文件名
request.FILES.get('1.jpg') # 获取上传的文件对象obj
obj -> 默认显示name,(内部__repr__函数)
obj.name
obj.size
obj.read() -> 读取整个上传文件的数据,文件较大时慎用。
obj.chunks() -> 一点一点获取数据块
obj.multiple_chunks(chunk_size=None) -> 判断文件是否足够大,默认2.5M,大于返回True
# 可用来判断使用read还是chunks
obj.content_type -> 上传文件时的content_type报头,例如(e.g. text/plain or application/pdf).
obj.charset -> 编码
- 获取文件:
f = open(obj.name,'wb')
for i in obj.chunks():
f.write(i)
f.close()

d. FBV & CBV 两种函数定义方式

  • FBV: function base view 一般函数

    path('index/', views.index),

    ./view.py
    def index(request):
    ...

  • CBV: class base view 类里的函数

    path('home/', views.Home.as_view()), # 类名.as_view()

    ./view.py
    from django.views import View
    class Home(View): # 继承View
    def get(self,request) # 请求GET时执行

    def post(self,request) # 请求POST时执行

    其他函数

    def dispatch(self,request): # View父类里负责判断method的函数,自动继承,可重定义

    def as_view(self,request): # 从url转到类中首先执行的方法,默认

两者没有明显优劣,建议:两者都用

e. 装饰器

def auth(func):
def inner(reqeust,*args,kwargs):
v = reqeust.COOKIES.get('username111') # 验证登录状态
if not v:
return redirect('/login/')
return func(reqeust, *args,
kwargs)
return inner

  • FBV装饰器:

    @auth
    def index(request):
    ...

  • CBV装饰器:

    from django import views
    from django.utils.decorators import method_decorator

    @method_decorator(auth,name='dispatch') # 装饰所有请求装饰,dispatch,与在dispatch函数前加装饰效果一致
    class Order(views.View):

    @method_decorator(auth) # 仅装饰get

    def get(self,reqeust):
    v = reqeust.COOKIES.get('username111')
    return render(reqeust,'index.html',{'current_user': v})

    def post(self,reqeust):
    v = reqeust.COOKIES.get('username111')
    return render(reqeust,'index.html',{'current_user': v})

模板html

a.母版

访问子板时引用母版,并替换母版的同名block块,然后渲染

  • 母板:

    {% block title %} {% endblock %} # 可放置在任意位置

  • 子板:

    {% extends "base.html" %} # 开头声明母版路径
    {% block title %}
    ...

写自己的css和js时,也要封装成分别的css和js的block块

b.小模块导入

将重复的标签块封装成小模块再导入

{% include 'tag.html' %} # 可重复导入

c.模板函数 |

{{ item.event_start|date:"Y-m-d H:i:s"}}
{{ bio|truncatewords:"30" }} # 变量前30个字符,用于中文不行
{{ content |slice:"30" }}       # 变量前30个字符,可用于中文
{{ my_list|first|upper }}

d.自定义函数

  • simple_tag

    <1> app下创建templatetags目录 # 不可改名

    <2> 创建任意xxxx.py文件

    <3> 在.py文件内创建template对象 register # 不可改名
    from django import template
    register = template.Library()

    <4> 用simple_tag装饰.py内的函数
    @register.simple_tag
    def func1(a1,a2,a3....) # 可传任意参数
    return "asdfasd"

    <5> 在settings中注册APP

    <6> 在html顶部引用函数(文件名)

    <7> 使用函数

    - 缺点:
    不能作为if条件
    - 优点:
    参数任意

  • filter

    <1><2><3><5><6>同上

    <4> 用filter装饰.py内的函数
    @register.filter
    def func2(a1,a2) # 只能最多两个参数
    return "asdfasd"

    <7> 使用函数

    - 缺点:
    最多两个参数,不能加空格
    要使用多个参数需要将参数传入同一个形参,在函数内部实现分离
    - 优点:
    能作为if条件

posted @ 2020-07-05 22:53  Jerome12138  阅读(133)  评论(0)    收藏  举报