路由和orm

一、起步
    1、安装django:
        pip install Django
        安装成功之后会在python安装目录下面生成django-admin.py和django-admin.exe文件
    2、创建工程:
        django-admin startproject m9d5
    3、创建app
        python manage.py startapp app01
    4、启动服务
        python manage.py makemigrations
        python manage.py migrate
        python manage.py runserver 127.0.0.1:8001
    5、设置静态文件和模板文件的目录
        1、找到settings.py里面,在最下面加上:
            STATIC_DIRS = (os.path.join(BASE_DIR, 'static'),)
        2、设置模板文件路径,settings.py里面找到TEMPLATES对应的列表,在DIRS所在的列表里面添加:
            'DIRS': [os.path.join(BASE_DIR, 'templates'),],
       
二、路由:
    """
    路由后面的斜杠要加都加,要不加都不加
    """
    #基础一对一
    path('cmdb/', views.index),    
    path('cmdb/login/', views.login),
    path('cmdb/home/', views.home),
    
    # CBV的路由书写方式
    path('cmdb/welcome/', views.Welcome.as_view()), 
    
    #利用正则,多个url对应一个函数 需要from django.urls import re_path
    re_path('cmdb/detail-(\d+).html', views.detail),
    re_path('cmdb/detail-(?P<nid>\d+)-(?P<uid>\d+).html', views.detail),
    
    #用name字段程序更加灵活,模版文件里用{% url 'r1' %},修改url的时候的不用改模版地址
    path('cmdb/host/', views.host, name="r1"),
    
    """
    模版文件里用{% url 'r1' num1 num2 %}
    {% url 'r1' pid=num1 uid=num2 %}
    如果要获取完整url,可以利用<form action="{{ request.path_info }}">
    request.path_info获取当前url
    """
    re_path('cmdb/host-(\d+)-(\d+)', views.host, name="r2"),
    
    """
    如果要根据接收的路由生成新的路由
    from django.urls import reverse
    可根据路由是位置参数还是关键字参数,选择使用args还是kwargs
    v = reverse('route_name', args=(3, 5), kwargs={'nid':3, 'uid':5})
    """
    re_path('cmdb/host-(?P<nid>\d+)-(?P<uid>\d+)', views.host, name="r3"),
    
    --------------------
    路由分发:
        #app01的url请求分发到app01下面的urls路由文件里
        #app02的url请求分发到app02下面的urls路由文件里
        urlpatterns = [
            path('admin/', admin.site.urls),
            path('app01/', include('app01.urls')),
            path('app02/', include('app02.urls')),
        ]
        然后在app01和app02的urls.py里面添加from app01 import views和from app02 import views
三、Model数据库操作:
    ORM分为两种,db first和code first
    db first: 先执行原生sql语句创建表,再用对象去操作
    code first: 先创建类,然后用类去创建表和操作数据库 如:django和sqlalchemy
    数据库接口在models.py里
    1、创建类
    from django.db import models
    # Create your models here.

    class UserInfo(models.Model):
        username = models.CharField(max_length=32)
        password = models.CharField(max_length=64)
    2、注册app
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app01',    #增加此项
    ]
    3、执行
    python manage.py makemigrations   #在migrations里面创建记录
    python manage.py migrate            #根据记录创建表结构
    
    如果在已有的表上新增一列:
    class UserInfo(models.Model):
        username = models.CharField(max_length=32)
        password = models.CharField(max_length=64)
        age = models.IntegerField()    
    运行python manage.py makemigrations的时候会有两种选择:
        1、在cmd里给定一个默认值;
        2、在models.py里面age = models.IntegerField(null=True)
    
    注意如果要用mysql:
    django默认使用mysqldb模块连接mysql,python3没有
    要在project同名目录下的__init__.py里面加上如下:
    import pymysql
    pymysql.install_as_MYSQLdb()
    4、外键操作
        创建表
            class Users(models.Model):
                uid = models.AutoField(primary_key=True)
                name = models.CharField(max_length=32)
                user_group = models.ForeignKey('UserGroup', on_delete=models.CASCADE)
            
            class UserGroup(models.Model):
                gid = models.AutoField(primary_key=True)
                section = models.CharField(max_length=32)
        创建数据
            #创建部门表数据
            # models.UserGroup.objects.create(section='技术')
            # models.UserGroup.objects.create(section='行政')
            # models.UserGroup.objects.create(section='财务')
            #创建职员表数据,user_group是django类,数据库给外键自动增加_id后缀
            # models.Users.objects.create(name='Eric', user_group_id=1)
            # models.Users.objects.create(name='Alice', user_group_id=2)
            # models.Users.objects.create(name='Tom', user_group_id=3)
        数据查询的三种方式:
            models.Users.objects.all()            #取出users表里的所有数据,QuerySet,内部都是对象
            python取出方法:
            for i in user_list:
                print(i.uid, i.name, i.user_group.section)
            html取出方法:
            {% for i in item %}
                {{ i.id }}
            {% endfor %}
            -----------------------------------------------------------
            models.Users.objects.all().values('uid', 'name', 'user_group__section')  #QuerySet,内部都是字典类型[{'uid':1, 'name':'Eric'}, {}, ...] 
            python取出方法:
            for i in user_list:
                print(i['uid'], i['name'], i['user_group__section'])
            html取出方法:
            {% for i in item %}
                {{ i['id'] }}            
                {{ i.['name'] }}            只能取这两个字段
            {% endfor %}
            -----------------------------------------------------------
            models.Users.objects.all().values_list('uid', 'name')  #QuerySet,内部都是元组类型 [(1, 'Eric'), (2, 'Alice'), ...]
            python取出方法:
            for i in user_list:
                print(i[0], i[1])
            html取出方法:
            {% for i in item %}
                {{ i.0 }}
                {{ i.1 }}
            {% endfor %}
            #获取一个对象,如果不存在就报错
            models.Users.objects.get(id=1)
            #获取一个对象,如果不存在就返回None
            models.Users.objects.filter(id=1).first()
            models.Users.objects.filter(id__gt=1)    #gt=greatthan lt=litterthan
        关联查询的三种方式:
            方式一:
            user_list = models.Users.objects.all()
            for i in user_list:
                # i.user_group是UserGroup object
                print(i.uid, i.name, i.user_group.section)
            方式二:
            models.Users.objects.filter(id__gt=0).values('uid', 'user_group_id', 'user_group__section')
            
        {{ forloop.counter }}      #正序从1开始计数
        {{ forloop.counter0 }}     #正序从0开始计数
        {{ forloop.revcounter }}   #倒序从1开始计数
        {{ forloop.revcounter0 }}  #倒序从1开始计数
        {{ forloop.first }}        #是否第一个计数    第一个True其他False
        {{ forloop.last }}         #是否最后一个计数  最后一个True其他False
        {{ forloop.parentloop }}   #父循环的信息,是一个字典
        
        多对多数据表的创建:
            方式一:自定义第三张表,好处是字段数可以自定义添加
                #主机表
                class Host(models.Model):
                    host_name = models.CharField(max_length=32)
                #应用表
                class Application(models.Model):
                    app_name = models.CharField(max_length=32)
                #主机和应用的关系连接表
                class AppToHost(models.Model):
                    hid = models.ForeignKey(to='Host', to_field="id")
                    aid = models.ForeignKey(to='Application', to_field="id")
                    
            方式二:django自动创建第三张表,缺点是第三张表只有三个字段,不能主动添加
                #主机表
                class Host(models.Model):
                    host_name = models.CharField(max_length=32)
                #应用表
                class Application(models.Model):
                    app_name = models.CharField(max_length=32)
                    r = models.ManyToManyField('Host')        #自动生成第三张表
                    
                第三张表的名字是:app01_application_r    字段名是application_id和host_id
                要添加关系,方法如下:
                    obj = models.Application.get(id=1)
                    obj.r.add(1)            # application_id=1 host_id=1
                    obj.r.add(2,3,4)
                    obj.r.add(*[2,3,4])     # 把id为1的application关联2,3,4
                    obj.r.remove(1)
                    obj.r.remove(*[2,3])      #移除
                    obj.r.remove(2,3)
                    obj.r.clear()           #清除application_id=1的所有
                    obj.r.set([1,2,3])      #去掉原先的关系,设置为新值
                

四、ajax无跳转发送数据
    $.ajax({
        url:'/app01/index'       //url地址
        type: 'POST'             //提交方式
        data:{                      //提交的数据 也可以$('#form_id').serialize()表单全部序列化
            'username':'Eric',
        }
        dataType:'JSON',          //默认success返回的数据都是字符串,如果要转换为json要用parse(),加上这个字段可以返回json格式
        traditional:true,          //加上此字段,发送的数据可以直接写列表,django端接收用getlist()
        success:function(data){    //数据发送成功后的回调函数
        
        },
        error:function(){          //错误信息接收函数
        },
    })
    
    ajax后台接收到数据,可以两种返回方式:HttpResponse和render
    HttpResponse更加灵活,可以返回字典类型的数据
    render只能返回字符串
    ajax不能用redirect返回数据:如果想跳转,可以在前端里面用js跳转,location.reload()和location.href='url'
    
五、视图获取请求相关信息
    def home(request):
        print(type(request)) # from django.core.handlers.wsgi import WSGIRequest
        # for k, v in request.environ.items():
            # #循环输出请求头对应字段和内容
            # print(k, v)
        print(request.environ['HTTP_USER_AGENT'])   #打印客户端的代理信息
        return HttpResponse('app01, home')
六、模板继承和模板导入
    公共模板:
        <!doctype html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Document</title>
            {% block css %}{% endblock %}
        </head>
        <body>
            <h1>My Blog</h1>
            {% block content %}{% endblock %}
            <script src='/static/jquery-1.12.4.js'></script>
            {% block js %}{% endblock %}
        </body>
        </html>
    应用模板的文件,extends只能继承一个模板,导入使用:{% include 'tag.html' %}
        {% extends 'master.html' %}
        {% block css %}
            <link rel="stylesheet" href="/static/common.css">
        {% endblock %}

        {% block content %}
            <div class='content' style="background-color:orange;">
                <p>据哈市警方撒娇的分公司地方</p>
                <p>据哈市警方撒娇的分公司地方</p>
                <p>据哈市警方撒娇的分公司地方</p>
                <p>据哈市警方撒娇的分公司地方</p>
                <p>据哈市警方撒娇的分公司地方</p>
            </div>
        {% endblock %}

        {% block js %}
            <script src='/static/my.js'></script>
        {% endblock %}
        
    simple_tag和filter
        {{ 'Eric'|lower }} 自带的filter把Eric变小写
        想创建自己的规则:
            一、在对应的app下面创建templatetags文件夹,在里面添加.py文件
            二、在模板文件里使用{% load py文件名不带后缀不加引号 %}
            py文件里的内容如下示例:
                from django import template
                from django.utils.safestring import mark_safe

                #死套路不能更改变量名
                register = template.Library()

                #套路
                @register.simple_tag
                def say(a, b):
                    return 'Hello', a+b

                @register.filter
                def play(a, b):
                    return 'basketball'

                @register.filter
                def eat(a, b):
                    return a+b
            如果是simple_tag,在模板里的使用方法:{% say 参数1 参数2 参数3 %} 函数名+空格+参数1+参数2
            如果是filter,在模板里的使用方法:{{ '参数1'|play:'参数2, 参数3' }}
            
            两种方式的优缺点:
                simple_tag
                    优点:参数数量不限制,直接后面跟空格+参数
                    缺点:不能做if条件
                filter
                    优点:可以做if条件
                    缺点:参数数量最低一个最多两个,使用方式如:{{ '参数1'|函数名:'参数2' }} 参数2也可以不加引号是个整数
                          如果要传多个参数,可以在参数2里面用字符串的形式传入,然后split分割出来
七、COOKIE
    # res是对象
    res = redirect('/app01/index')
    res.set_cookie('user1', username)    # 设置cookie,关闭浏览器失效
    request.COOKIES.get('user1')   #获取cookie
    set_cookie()的参数如下:
    key              键
    value            值 
    max_age=None     超时时间
    expires=None     超时时间(IE requires expires, so set it if hasn't been already.)
    path='/'         Cookie生效的路径,/表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
    domain=None      Cookie生效的域名
    secure=False     https传输
    httponly=False   只能http协议传输,无法被javascript获取(不是绝对,底层抓包可以获取到,也可以被覆盖)
    
八、小结
    request.body    http请求体
        request.POST(request.body)
        request.GET(request.body)
        request.FILES(request.body)
        request.xxxx.getlist
    request.Meta()  http请求头
        request.method
        request.path_info
        request.COOKIES
    return
        a = 'China'
        HttpResponse('字符串或者bytes')
        
        response = HttpResponse(a)
        response['name'] = 'Eric'   #显示在响应头内
        response.set_cookie()
        return response
        
        render
        redirect
    cookie
        存储在浏览器客户端的一个字典
        不设置超时时间,就是关闭浏览器失效
    session
        django的session是存储在数据库里,
        存储在服务端的一个字典,只给用户返回一个随机字符串作为通行证,
        用户再次请求,客户端字符串和服务端比较
        {
            'dfsdfdsfds':{...},
            'sdfgdfgf':{...},
        }
        # 生成随机字符串
        # 写到用户浏览器cookir
        # 保存在session中
        # 在随机字符串对应的字典中设置相应的内容...
        request.session['username'] = 'Eric'   # django就这一步就完成所有的session操作
        如果要判断用户是否登陆,request.session['is_login'] = True
        -------------
        session的操作:
            - session依赖于cookie
            - 服务器端session:
                request.session['k1']               # 取值,没有就报错
                request.session.get('k1', None)     # 取值,没有返回None
                request.session['k1'] = 123         # 设置值
                request.session.setdefault('k1', '123')    # 没有就设置默认值
                request.session.clear()
                del request.session['k1']     # 删除某个键
                # 所有键、值、键值对
                request.session.keys()
                request.session.values()
                request.session.items()
                request.session.iterkeys()
                request.session.itervalues()
                request.session.iteritems()
                # 用户sesssion的随机字符串
                request.session.session_key
                # 将所有session失效日期小于当前日期的数据删除
                request.session.clear_expired()
                # 检查用户session的随机随机字符串在数据库中是否存在
                request.session.exists('session_key')
                # 删除当前用户的所有session数据
                request.session.delete('session')
                # session的默认超时时间是两周
                request.session.set_expiry(value)
                    * 如果value是个整数,session会在秒数后失效
                    * 如果value是个datetime或timedelta,session就会在这个时间失效
                    * 如果value是0,用户关闭浏览器session会失效
                    * 如果value是None,session会依赖全局session失效策略。
            - 配置文件中设置默认操作:
                SESSION_COOKIE_NAME = 'sessionid'               # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
                SESSION_COOKIE_PATH = '/'                       # Session的cookie保存的路径(默认)
                SESSION_COOKIE_DOMAIN = None                    # Session的cookie保存的域名(默认)
                SESSION_COOKIE_SECURE = True                    # 是否Https传输cookie(默认)
                SESSION_COOKIE_AGE = 1209600                    # Session的cookie失效日期(2周)(默认)
                SESSION_EXPIRE_AT_BROWSER_CLOSE = False         # 是否关闭浏览器使得Session过期(默认)
                #登陆之后,失效日期从每次刷新之后开始计时
                SESSION_SAVE_EVERY_REQUEST = False              # 是否每次请求都保存Session,默认修改之后才保存(默认)
            django支持5种session模式
                1、数据库
                    SESSION_ENGINE = 'django.contrib.sessions.backends.db'
                2、缓存
                    SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
                    SESSION_CACHE_ALIAS = 'default'
                    CACHES = {
                        'default': {
                            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache'
                            'LOCATION': [
                                '172.19.26.240:11211',
                                '172.19.26.242:11211',
                            ],
                        },
                        'db1': {
                            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache'
                            'LOCATION': [
                                '172.19.26.240:11211',
                                '172.19.26.242:11211',
                            ],
                        },
                    }
                3、文件
                    SESSION_ENGINE = 'django.contrib.sessions.backends.file'
                    SESSION_FILE_PATH = None     #缓存文件路径,如果没None,则使用tempfile获取一个临时地址进行存储
                4、缓存+数据库
                    SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'
                5、加密cookie
                    csrf:GET请求页面,服务器发送加密字符串给页面,客户端携带加密字符串POST提交表单才被允许
                    
                    1、普通提交要在html表单里面加上{% csrf_token %},要不然就forbidden
                    2、ajax提交要携带随机字符串:
                        方法一:
                            $.ajax({
                                headers: {'X-CSRFtoken': $.cookie(csrftoken)},
                            })
                        方法二:
                            # 也可以用下面方式,为所有ajax请求设置请求头
                            $.ajaxSetup({
                                beforeSend: function(xhr, settings){
                                    xhr.setRequestHeader('X-CSRFtoken', $.cookie(csrftoken));
                                }
                            })
                    3、如果想为某个views单独设置csrf
                        from django.views.decorators.csrf import csrf_exempt, csrf_protect
                        # 不想用csrf就在函数前面加上 @csrf_exempt
                        # 想用csrf就在函数前面加上 @csrf_protect
九、中间件
    1、找到settings.py文件里面的MIDDLEWARE,里面加上自己的中间件路径:
        如:'Middle.m1.Row1'    # 工程目录下的Middle模块下面的m1文件里面的Row1类
        中间件的本质就是一个类
    2、中间件创建方法
        from django.utils.deprecation import MiddlewareMixin
        class Row1(MiddlewareMixin):
            def process_request(self, request):
                print('Eric')
            def process_request(self, request):
                pass
            def process_response(self, request, response):
                pass
            """
            @ view_func 对应的Views函数名
            @ view_func_args 路由中的位置参数的值
            @ view_func_kwargs 路由中的关键字参数的值
            """ 
            def process_view(self, request, view_func, view_func_args, view_func_kwargs):
                pass
            #异常处理
            def process_exception(self, request, exception):
                if isinstance(exception, ValueError):
                    return HttpResponse('出错')
            """
            如果views中的函数返回的对象中含有render方法执行此方法
            如果要httpresponse和redirect执行可以用下面方法
            Class Foo:
                def render(self):
                    return HttpResponse('OK')
            # Views函数
            def test(self, request):
                return Foo()        # 用此方法可以让process_template_response都执行
            """
            def process_template_response(self, request, response):
                return response    # 必须要返回response请求才会继续往下执行

中间件各方法图示: 

posted @ 2018-07-25 09:28  与君同悦  阅读(134)  评论(0编辑  收藏  举报