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, 'fgf.html', {'u': user_list})

fgf.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

fgf.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目录
    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 = {
    "fgf00":{"pwd":"123456"},
    "fgf01":{"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() 
                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
            /index/    name = 'n1'


            reverser('m1:n1')

    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://blog.csdn.net/fgf00/article/details/54018066

你可能感兴趣的:(django,cookie,simple-tag,母版继承)