• Django(五)母版继承、Cookie、视图装饰器等


    大纲

    一、内容回顾
    补充:默认值
    补充:命名空间
    二、模板语言
    1、母版继承
    2、include
    3、自定义simple_tag
    三、Cookie
    Cookie 使用总结
    四、视图
    1、获取用户请求相关信息以及请求头
    2、CBV和FBV用户认证装饰器

    二、模板语言

    1、母版继承

    母板:{% block title %}{% endblock %}
    子板:{% extends "base.html" %}        # 指定继承母版文件
       {% block title %}{% endblock %}

    示例:

    urls.py

    url(r'^model/', views.model),

    views.py

    def model(request):
        user_list = [1, 2, 3, 43]
        return render(request, 'lgeng.html', {'u': user_list})

    lgeng.html

    {% extends 'master.html' %}  {# 导入模板文件 #}
    
    {% block title %}用户管理{% endblock %}  {# 标题 #}
    
    {% block center %}  {# 内容 #}
        <h1>用户管理</h1>
        <ul>
            {% for i in u %}
                <li>{{ i }}</li>
            {% endfor %}
        </ul>
    {% endblock %}
    
    {% block css %}     {# 自定义css #}
        <style>
            body{
                background-color: white;
            }
        </style>
    {% endblock %}
    
    {% block js %}      {# 自定义js #}
        <script></script>
    {% endblock %}

    master.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>{% block title %}{% endblock %}</title>
        <link rel="stylesheet" href="/static/commons.css">
        <style>
            .pg-header{
                height: 48px;
                background-color: seashell;
                color: green;
            }
        </style>
        {% block css %}{% endblock %}  {# 自定义css使用 #}
    </head>
    <body>
        <div class="pg-header">主机管理</div>
        {% block center %}{% endblock %}
        <script src="/static/jquery.js"></script>
        {% block js %}{% endblock %}   {# 自定义js使用 #}
    </body>
    </html>

    2、include

    一个html只能继承一个母版,而对于一些小组件、经常使用的,可以通过导入实现。一个html中可以有多个include

    lgeng.html 内增加

    {% block center %}  # 内容
        <h1>用户管理</h1>
    
        {% for i in u %}        {# 可以循环导入 #}
            {% include 'tag.html' %}    {# include 导入 #}
        {% endfor %}
    
    {% endblock %}

    tag.html

    {{ u }}     {# 导入文件中也可以使用模板语言 #}
    <form>
        <input type="text" />
        <input type="submit" />
    </form>  

    django 是把所有母版、include 合并成一个总的字符串后,在进行渲染。

    3、自定义simple_tag

    比如在模板语言里,传入值5,让返回25,或传入一个列表只显示前三个,等对值的二次处理。

    在模板语言中,提供了部分内置功能。有些功能不够用时就需要自定义python函数实现。

    • 内置功能 —> simple_tag
    {{ time_obj|date:"Y-m-d H:i:s"}}  # 对传入转为日期时间格式
    {{ str_obj|truncatewords:"30" }}  # 截取前三十个字符
    {{ my_list|first|upper }}  # 把第一个字符大写
    {{ name|lower }}  # 把传入值小写
    • 自定义simple_tag

    分两种方式,总结如下

    # 两种方式相同配置
        a. app下创建templatetags目录  (templatetags模块 --- python package )
        b. 目录下任意xxoo.py文件,创建template对象 register
            from django import template
            register = template.Library()
    
    # 第一种方式:simple_tag
        c. 定义:装饰函数
            @register.simple_tag
            def func(a1,a2,a3....)
                return "asdfasd"
        d. 配置:settings中注册APP
        e. 引用:哪里用哪里顶部 {% load xxoo %}
        f. 使用:{% 函数名 arg1 arg2 %}
        # 缺点: 不能作为if条件
        # 优点: 参数任意
    
    # 第二种方式:filter
        c.定义:装饰函数
            @register.filter
            def func(a1,a2)
                return "asdfasd"
        d. 配置:settings中注册APP
        e. 引用:部 {% load xxoo %}  # 引用母版extend时,load在extend下面。
        f. 使用:{ 参数1|函数名:"参数二" }}  # 传多个,把参数二自定义“a,b,c”多个,自己处理
        # 缺点: 最多两个参数,不能加空格
        # 优点: 能作为if条件

    使用:

    app01/templatetags/xxoo.py

    from django import template
    
    register = template.Library()
    
    @register.simple_tag  # 第一种方式
    def houyafan(a1,a2):
        return a1 + a2
    
    @register.filter  # 第二种方式
    def jingze(a1,a2):
        return a1 + a2

    settings.py

    INSTALLED_APPS = [
        '……………………',
        'app01',
    ]

    templates/tpl4.html

    {% load xxoo %}
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>{% houyafan 2 7 %}</h1>
    
        <h1>{{ "maliya"|jingze:"Laoshi" }}</h1>
    </body>
    </html>

    urls.py url(r'^tpl', views.tpl),

    views.py

    def tpl(request):
        return render(request,"tpl4.html")

    三、Cookie

    把浏览器的cookie禁用掉,所有涉及到登录的网站都不能登录使用了。

    Cookie :客户端浏览器上的一个文件,类似于键值对字典存储。换浏览器就不行了。

    基于这个功能可以实现用户的登录认证,但cookie不是专门用来做用户验证登录的,只不过是利用这个特性实现用户登录。

    urls.py

    url(r'^login/', views.login),
    url(r'^index/', views.index),

    views.py

    from django.shortcuts import render, HttpResponse,redirect
    user_info = {
        "lgeng00":{"pwd":"123456"},
        "lgeng01":{"pwd":"123456"},
    }
    def login(request):
        if request.method =="GET":
            return render(request,"login.html")
        if request.method == "POST":
            u = request.POST.get("username")
            p = request.POST.get("pwd")
            dic = user_info.get(u)
            if not dic:
                return render(request,"login.html")
            if dic['pwd'] == p:
                res = redirect('/index/')
                res.set_cookie("username111", u)    ## 设置cookie
                return res
            else:
                return render(request,'login.html')
    
    def index(request):
        # 获取当前已登录的用户
        v = request.COOKIES.get("username111")
        if not v:
            return redirect('/login/')
        return render(request,'index.html',{'current_user': v})

    login.html

    <body>
        <form action="/login/" method="POST">
            <input type="text" name="username" placeholder="用户名" />
            <input type="password" name="pwd" placeholder="密码" />
            <input type="submit" />
        </form>
    </body>

    index.html

    <body>
        <h1>欢迎登录:{{ current_user }}</h1>
    </body>

    1、获取Cookie:

    request.COOKIES['key']
    request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
        参数:
            default: 默认值
               salt: 加密盐
            max_age: 后台控制过期时间

    2、设置Cookie:

    rep = HttpResponse(...) 或 rep = render(request, ...)
    
    rep.set_cookie(key,value,...)
    rep.set_signed_cookie(key,value,salt='加密盐',...)
        参数:
            key,             键
            value='',        值
            max_age=None,    超时时间
            expires=None,    超时时间(IE requires expires, so set it if hasn't been already.)
            path='/',        Cookie生效的路径,/ 表示根路径,特殊的
            跟路径的cookie可以被网站的任何url的页面访问,如"/index",只能index下能访问
            domain=None,     Cookie生效的域名,在哪个子url下生效
            secure=False,    https传输(https时,设为ture)
            httponly=True    只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
    def cookie(request):
    # 获取 Cookie
        # request.COOKIES                   # 客户端发来的所有Cookie
        # request.COOKIES['username111']    # 这个Cookie,就是字典
        request.COOKIES.get('username111')
    
    # 设置 Cookie
        res = render(request,'index.html')
        res = redirect('/index/')
    
        res.set_cookie('key',"value")  # 设置cookie,关闭浏览器失效
        res.set_cookie('key',"value",max_age=10)  # 设置cookie, N秒后失效
    
        # expires:设置cookie, 截止时间后失效
        import datetime
        current_date = datetime.datetime.utcnow()
        current_date = current_date + datetime.timedelta(seconds=5)
        res.set_cookie('key',"value",expires=current_date)
    # cookie 加密盐
        obj = HttpResponse('s')
        obj.set_signed_cookie('username',"kangbazi",salt="asdfasdf") # 加密盐
        request.get_signed_cookie('username',salt="asdfasdf")  # 加密盐获取

    四、视图

    1、获取用户请求相关信息以及请求头

    客户端发来的数据不只是get、post、文件等信息,还有基本的请求头,cookie、session等

    想查看客户端发来的数据request提供了哪些方法?

    • 先找到对象的类:print(tyep(request))

    • 导入类,查看类的内容 from django.core.handlers.wsgi import WSGIRequest

      request.environ 封装了所有用户请求信息,原生数据

      from django.core.handlers.wsgi import WSGIRequest
      
      for k,v in request.environ.items():
        print(k,v)
      print(request.environ['HTTP_USER_AGENT'])  # 客户端终端信息

    2、CBV和FBV用户认证装饰器

    urls.py

        url(r'^login/', views.login),
        url(r'^index/', views.index),
        url(r'^order/', views.Order.as_view()),

    views.py

    ######################  装饰器函数  ###########################
    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(reqeust):
        # 获取当前已经登录的用户
        v = reqeust.COOKIES.get('username111')
        return render(reqeust,'index.html',{'current_user': v})
    ######################  FBV 认证装饰  #########################
    from django import views
    from django.utils.decorators import method_decorator  # 需要导入模块
    
        #****** 第三种:给类加、指定dispatch,同第二种,不需要多写个函数 ******
    @method_decorator(auth,name='dispatch')
    class Order(views.View):
    
        # @method_decorator(auth)  #===== 第二种:dispatch加,方法均有 =====
        # def dispatch(self, request, *args, **kwargs):
        #     return super(Order,self).dispatch(request, *args, **kwargs)
    
        # @method_decorator(auth)  #--------- 第一种:每个函数都加 ---------
        def get(self,reqeust):
            v = reqeust.COOKIES.get('username111')
            return render(reqeust,'index.html',{'current_user': v})
        # @method_decorator(auth)  #--------- 第一种:每个函数都加 ---------
        def post(self,reqeust):
            v = reqeust.COOKIES.get('username111')
            return render(reqeust,'index.html',{'current_user': v})

    一、之前内容回顾

    1、请求周期
            url> 路由 > 函数或类 > 返回字符串或者模板语言?
    
            Form表单提交:
                提交 -> url > 函数或类中的方法 
                                    - ....
                                    HttpResponse('....')
                                    render(request,'index.html')
                                    redirect('/index/')
                 用户  <————  返回字符串
                 (当接受到redirect时)自动发起另外一个请求
                 --> url   .....
    
            Ajax:
                $.ajax({
                    url: '/index/',
                    data: {'k': 'v', 'list': [1,2,3,4], 'k3': JSON.stringfy({'k1': 'v'})},    // $(form对象).serilize()  
              //data:$('form').serilize() //-->:user=abc&pwd=aa&add=abc&email=aba&birth=aba&group_id=3 type:
    'POST', dataType: 'JSON': traditional: true, # 使单值、列表等都可以发向后台 success:function(d){ location.reload() # 自己刷新 location.href = "某个地址" # 自己跳转 } }) 提交 -> url -> 函数或类中的方法 HttpResponse('{}') render(request, 'index.html', {'name': 'v1'}) <h1>{{ name }}</h1> --> <h1>v1</h1> redirect...Ajax里不可以 用户 <<<<< 字符串 2、路由系统URL a. /index/ -> 函数或类 b. /index/(d+) -> 函数或类 c. /index/(?P<nid>d+) -> 函数或类 d. /index/(?P<nid>d+) name='root' -> 函数或类 reverse() {% url 'root' 1%} e. /crm/ include('app01.urls') -> 路由分发 f. 默认值 # url第三个参数作为默认参数传递到view函数里 url(r'^index/', views.index, {'name': 'root'}), def index(request,name): print(name) return HttpResponse('OK') g. 命名空间 /admin/ include('app01.urls',namespace='m1') /crm/ include('app01.urls',namespace='m2')
    app01.urls

    app_name = 'app01' <-- 添加 app_name
    urlpatterns=[   url(r'/
    index/', views.index, name = 'n1'),
             url(r'/home/' , views.home, name = 'n2)'
            ]
    reverser('m1:n1') --> /admin/index/
    reverser('m1:n2') --> /admin/home/
    reverser('m2:n1') --> /crm/index/
    reverser('m2:n2') --> /crm/home/
           
    3、获取请求 def func(request): request.POST request.GET request.FILES request.getlist request.method request.path_info return render,HttpResponse,redirect 4、模板 render(request, 'index.html') # for # if # 索引 用 . keys values items all (都不加括号) 5、数据库操作 class User(models.Model): username = models.CharField(max_length=32) email = models.EmailField() 有验证功能 Django Admin 无验证功能: User.objects.create(username='root',email='asdfasdfasdfasdf') User.objects.filter(id=1).update(email='666') class UserType(models.Model): name = models.CharField(max_length=32) # 外键 class User(models.Model): username = models.CharField(max_length=32) email = models.EmailField() user_type = models.ForeignKey("UserType") # 数据库操作 user_list = User.objects.all() # 获取对象列表 for obj user_list: obj.username,obj.email,obj.user_type_id,obj.user_type.name,obj.user_type.id user = User.objects.get(id=1) # 获取单个对象 user. # 对象跨表用点,条件里用双下划线 User.objects.all().values("username","user_type__name",) # 多对多 class UserType(models.Model): name = models.CharField(max_length=32) class User(models.Model): username = models.CharField(max_length=32) email = models.EmailField() user_type = models.ForeignKey("UserType") m = models.ManyToMany('UserGroup') class UserGroup(models.Model): name = .... obj = User.objects.get(id=1) obj.m.add(2) obj.m.add(2,3) obj.m.add(*[1,2,3]) obj.m.remove(...) obj.m.clear() obj.m.set([1,2,3,4,5]) # 这里列表前不加* # 多个组,UserGroup对象 obj.m.all() obj.m.filter(name='CTO')

    补充:默认值

    看上面内容

    补充:命名空间

    a. project.urls.py

    两个url同指向一个

    from django.conf.urls import url,include
    
    urlpatterns = [                     # namespace  命名空间
        url(r'^a/', include('app01.urls', namespace='m1')),
        url(r'^b/', include('app01.urls', namespace='m2')),
    ]

    b. 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')
    ]

    c. app01.views.py

    def detail(request):
        return HttpResponse('pk')

    以上定义带命名空间的url之后,使用name反向生成URL(反解)的时候,应该如下:

    • v = reverse('m1:detail') python代码里
    • {% url 'm1:detail' %} 模板语言里

    django中的路由系统和其他语言的框架有所不同,在django中每一个请求的url都要有一条路由映射,这样才能将请求交给对一个的view中的函数去处理。其他大部分的Web框架则是对一类的url请求做一条路由映射,从而使路由系统变得简洁。


    转载请务必保留此出处:http://www.cnblogs.com/lgeng/articles/7365723.html

     <!--   END   -->

    《版权说明》: 本文转自 -- http://blog.csdn.net/fgf00/article/details/54018066

  • 相关阅读:
    CDZSC_2015寒假新人(4)——搜索 A
    第一次组队赛---2010年全国大学生程序设计邀请赛(福州)L
    ZSC新生赛 沼跃鱼早已看穿了一切
    ZSC新生赛 聪明的员工
    CDZSC_2015寒假新人(1)——基础 I
    Linux 系统时间和硬件时间
    Python 深浅复制
    Python 函数内省
    Python 函数参数
    Python 可调用对象
  • 原文地址:https://www.cnblogs.com/lgeng/p/7365723.html
Copyright © 2020-2023  润新知