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<nid>\d+)-(?P<uid>\d+).html', views.detail)
      
      def func(request, *args, **kwargs):
          kwargs = {'nid': 1, 'uid': 3}
    

新版使用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<year>[0-9]{4})/$', views.year_archive),
      re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
      re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[\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('<username>/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/page<int: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 %}
          ...
      {% endblock %}
    

写自己的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 }}
{{ name|lower }}

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顶部引用函数(文件名)
          {% load xxoo %} 
    
      <7> 使用函数
          {% func1 arg1 arg2 %}       # 空格不影响,用{% %}
    
      - 缺点:
          不能作为if条件
      - 优点:
          参数任意
    
  • filter

      <1><2><3><5><6>同上
    
      <4> 用filter装饰.py内的函数
          @register.filter
          def func2(a1,a2)            # 只能最多两个参数
              return "asdfasd"
    
      <7> 使用函数
          {{ 'arg1'|func2:'arg2' }}       # 中间不能加空格,用{{|}}
    
      - 缺点:
          最多两个参数,不能加空格
          要使用多个参数需要将参数传入同一个形参,在函数内部实现分离
      - 优点:
          能作为if条件
          {% if arg1|func2:arg2 %}
          {% end if %}
    
posted @ 2020-07-05 22:53  Jerome12138  阅读(116)  评论(0编辑  收藏  举报