python Django 相关学习笔记

Django框架
    pip3 install django
    
    命令:
        # 创建Django程序
        django-admin startproject mysite
        # 进入程序目录
        cd mysite
        # 启动socket服务端,等待用户发送请求
        python manage.py runserver 127.0.0.1:8080
        # 创建app
        python manage.py starapp app01
        
    pycharm
    1. 创建project
    2. 配置:
        - 模板路径
            template目录
            TEMPLATES = [{
                    'BACKEND': 'django.template.backends.django.DjangoTemplates',
                    'DIRS': [os.path.join(BASE_DIR, 'template')],
                    'APP_DIRS': True,
                    'OPTIONS': {
                        'context_processors': [
                            'django.template.context_processors.debug',
                            'django.template.context_processors.request',
                            'django.contrib.auth.context_processors.auth',
                            'django.contrib.messages.context_processors.messages',
                        ],},},]
        - 静态文件路径
            static目录
            STATIC_URL = '/static/'
            STATICFILES_DIRS = (
                os.path.join(BASE_DIR,'static'),
            )

    3. 额外配置
        MIDDLEWARE = [#'django.middleware.csrf.CsrfViewMiddleware',]
        
    

Web框架本质

浏览器(socket客户端)
        2. 发送IP和端口  http://www.baidu.com:80/index/
            GET:
                请求头                    http1.1 /index?p=123
                请求体(无内容)
            POST:
                请求头                    http1.1 /index?p=123
                请求体                    ...
        4. 接收响应
            普通响应:页面直接显示
            重定向响应:再一起一次Http请求

    服务器(socket服务端)
        1. 启动并监听ip和端口,等待用户连接
        3. 接收请求进行处理,并返回
            普通返回:
                响应头:
                    Access-Control-Allow-Origin:*

                响应体:
                    <html>...</html>
            重定向返回:
                响应头:
                    LOCATION: 'http://www.baidu.com'
                    Access-Control-Allow-Origin:*

 

 

路由系统:

urls.py
from django.urls import path,re_path
from app01 import views

urlpatterns = [
    # path('admin/', admin.site.urls),
    path('index/', views.index),
    re_path('^edit/(\w+)/$',views.edit1),        # 加上 $  
    re_path('^edit/(\w+).html$',views.edit2),
    re_path('^edit/(?P<a2>\w+)/(?P<a1>\w+).html$',views.edit3), 
    # 按参数名传参    # def edit3(request,*args,**kwargs):
    # 不要将(\w+)与(?P<a2>\w+)混用
    # 如果前面不加结尾符,则不能匹配此url
    
    path('index2/', views.index2,name='n2'),
    # 给url命名;在函数中通过别名反找到url
    re_path('index3/(\w+)', views.index3,name='n3'),
    # 可随意生成(\w+)位置的值
    re_path('^index4/(?P<a2>\w+)/(?P<a1>\w+).html$', views.index4,name='n4'),
    # 可随意生成(?P<a2>\w+)位置的值
    
    re_path('^', default),    
    # 此规则放最后
    # 什么都不输或者输错了,将会被匹配    # def default(request):return HttpResponse('url 错误')
]


views.py
def edit(request,a1):
    # a1 为re_path('^edit/(\w+)/$')括号中的字符,按位置传参,
    # 若url中有2个括号,函数就有request参数和另2个参数
    return HttpResponse('...')
    
# 通过别名反找到url,反生成url
from django.urls import reverse
def index2(request):
    v = reverse('n2')
    return HttpResponse(v)
    
def index3(request,*args):
    v = reverse('n3',args=(123,))    
    # 请求url:index3/3        生成url:index3/123
    # 有多少(\w+),args=(,)就写多少个参数
    return HttpResponse(v)
    
def index4(request,**kwargs):
    v = reverse('n4',kwargs={'a2':666,'a1':777))        # /index4/666/777.html
    # 请求url:index3/3        生成url:index3/123
    # 有多少(?P<a2>\w+),kwargs={,}就写多少个键值对
    return HttpResponse(v)
    
# 若是给url命名,在templates模板中可以直接使用名字{% url 'm1' %}
# path('index10/', views.index10,name='m1'),
# <form method="post" action="{% url 'm1' %}">        # -><form method="post" action="/index10/">
# re_path('index10/(\w+)/', views.index10,name='m2'),
# <form method="post" action="{% url 'm3' 'abc' %}">    # "补位"
    
url 的常用使用

 

    
路由分发:
    urls.py分配url到app
    from django.urls import path,re_path,include
    urlpatterns = [
        path('app02/', include('app02.urls')),
        path('app01/', include('app01.urls')),    
            # 只匹配开头,然后交与app01中的urls继续匹配
            # 请求url为 http://127.0.0.1:8000/app01/index/        
            # -> 先匹配到app01 -> app01下的urls中匹配index
    ]

    在app01.urls.py文件下匹配url
    from django.urls import path,re_path
    from app01 import views

    urlpatterns = [
        path('index/', views.index),
    ]
    
    
路由分发

 

ORM操作

ORM操作 (Django2.1.8)
    Http请求:
        url -> 视图(模板+数据)
    步骤:
        1. 创建数据库
        2. 
            DATABASES = {
                'default': {
                    'ENGINE': 'django.db.backends.mysql',
                    'NAME':'s4day70db',
                    'USER': 'root',
                    'PASSWORD': '',
                    'HOST': 'localhost',
                    'PORT': 3306,
                    }
            }
        3. __init__文件中
            import pymysql
            pymysql.install_as_MySQLdb()
        
        4.注册app
            INSTALLED_APPS = [app01,]
            
        5.    from django.db import models
            class UserGroup(models.Model):
                title = models.CharField(max_length=32)

            class UserInfo(models.Model):
                nid = models.BigAutoField(primary_key=True)
                user = models.CharField(max_length=32)
                password = models.CharField(max_length=64)
                age = models.IntegerField(default=1)
                ug = models.ForeignKey('UserGroup',on_delete=models.CASCADE,null=True)
                # 联合唯一
                class Meta:
                    unique_together = [
                        ('b','g'),]

        6.创建数据表,命令:
            python manage.py makemigrations
            python manage.py migrate
			# 报错django.db.utils.InternalError: (1366, "Incorrect string value: '\\xE8\\x8B\\xB1\\xE8\\xAF\\xAD...' for column 'name' at row 1")
			# 解决方法,数据库设置默认编码 default charset=utf8
            
    # orm中,若不手动创建models.AutoField(primary_key=True),则自动创建id列。
    # 已经创建好的数据库表,修改后重新在终端执行命令即可修改。
    # 在已有列的表中增加列,设置值为空null=True,或者default=''设置默认值。
    外键:
        UserInfo表中生成外键,列名为 ug_id
        ug(对象)    代表UserGroup中的一行数据
        
    增
        models.UserGroup.objects.create(title='销售部')
        obj = models.UserGroup.objects.create(title='销售部')
        print(obj.id)    # 返回创建好的数据
        
        obj = models.UserGroup(title='xxx')
        obj.save()
        
        # 批量插入数据
        objs = [
            models.UserGroup(name='name-1'),
            models.UserGroup(name='name-2'),
        ]
        models.UserGroup.objects.bulk_create(objs,10)
    查
        # 类->数据库表,对象->数据表行
        group_list = models.UserGroup.objects.all()        # 获取所有数据
        # for row in group_list:
        #     print(row.id,row.title)
        group_list = models.UserGroup.objects.filter(id__gt=1) # filter(筛选条件) QuerySet[obj,obj]
        group_list = models.UserGroup.objects.filter(id__gt=1).first() # 取第一个值,obj对象
        
        obj = models.UserInfo.objects.filter(id__gt=1).first()
        obj.ug.title 
        # 含外键表查寻,对象.外键表列名 即可获取主表的值。
            
        models.UserGroup.objects.all().values('id','title')            # 字典类型,两列。
        models.UserGroup.objects.all().values_list('id','title')    # 元组类型,两列。
        
        obj = models.UserGroup.objects.filter(id__gt=1).first()
        obj.userinfo_set.all()        # obj.userinfo_set.filter(nid=2)对另一张表的列做筛选
        # 反向操作,获取已被关联外键项的所有与之关联的数据!?    # obj.表名小写_set.all()
        for row in obj.userinfo_set.all():
            # 获取到的是userinfo 中的数据
            print(row.age,row.user)
        
        models.UserGroup.objects.all().values('id','title','userinfo__age')    # 反向查找,跨表
        models.UserInfo.objects.all().values('nid','ug__title',)            # 正向查时跨表
        models.UserInfo.objects.all().values_list('nid','ug__title',)        # 正向查时跨表
        # xxx.filter() 也可以跨表,跟value一样。
        
        # 查询主动做连表
        models.UserInfo.objects.all().select_related('ug')
        # 不做连表,做多次查询
        models.UserInfo.objects.all().prefetch_related('ug')
        
        user_list = models.UserInfo.objects.all()[page_info.start():page_info.end()]    # 分页,获取某段数据
        
        # 排序
        models.UserInfo.objects.order_by('nid')    # 从大到小
        models.UserInfo.objects.order_by('-nid','name')    # 从小到大,id重复按name排序
        
        # 分组
        from django.db.models import Count,Sum,Min
        user_list = models.UserInfo.objects.values('ug_id').annotate(xxx = Count('nif'))
        # print(user_list,user_list.query)
        # <QuerySet [{'xxx': 10, 'ug_id': 1}]> SELECT `app01_userinfo`.`ug_id`, COUNT
        # (`app01_userinfo`.`nid`) AS `xxx` FROM `app01_userinfo` GROUP BY
        # `app01_userinfo`.`ug_id` ORDER BY NULL
        # user_list = models.UserInfo.objects.values('ug_id').annotate(xxx = Count('nid')).filter(xxx__gt=3)
        # 分组后筛选
        # <QuerySet [{'xxx': 10, 'ug_id': 1}]> SELECT `app01_userinfo`.`ug_id`, COUNT
        # (`app01_userinfo`.`nid`) AS `xxx` FROM `app01_userinfo` GROUP BY
        # `app01_userinfo`.`ug_id` HAVING COUNT(`app01_userinfo`.`nid`) > 3 ORDER BY NULL
        
        # 其它
        models.UserInfo.objects.filter(id__lt=1)    # <
        models.UserInfo.objects.filter(id__gte=1)    # >=
        models.UserInfo.objects.filter(id__in=[1,2,3])    # in[1,2,3,]
        models.UserInfo.objects.filter(id__range=[1,3])
        models.UserInfo.objects.filter(id=1)
        models.UserInfo.objects.exclude(id=1)    # id !=1
        
        
        # Q
        # 方式一
            models.UserInfo.objects.filter(Q(nid=8) | Q(nid__gt=10) & Q(caption='root'))
        # 方式二 组合查询
            q1 = Q()
            q1.connector = 'OR'
            q1.children.append(('id', 1))
            q1.children.append(('id', 9))
            
            q2 = Q()
            q2.connector = 'OR'
            q2.children.append(('c1', 1))
            q2.children.append(('c1', 10))
            
            con = Q()
            con.add(q1, 'AND')
            con.add(q2, 'AND')
            models.Tb1.objects.filter(con)
            
        # extra 
        # extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
            result = models.UserInfo.objects.filter(id__gt=1).extra(
                    where=['app01_userinfo.id < %s'],
                    params=[100,],
                    tables=['app01_usertype'],
                    order_by=['-app01_userinfo.id'],
                    select={'uid':1,'sw':"select count(1) from app01_userinfo"}
                )
                print(result.query)
                # SELECT (1) AS "uid", (select count(1) from app01_userinfo) AS "sw", "app01_userinfo"."id", "app01_userinfo"."name", "app01_userinfo"."age", "app01_userinfo"."ut_id" FROM "app01_userinfo" , "app01_usertype" WHERE ("app01_userinfo"."id" > 1 AND (app01_userinfo.id < 100)) ORDER BY ("app01_userinfo".id) DESC
            
        
        
        # 执行原生SQL
            from django.db import connection, connections
            cursor = connection.cursor()  
            # cursor = connections['指定数据库'].cursor()
            cursor.execute("""SELECT * from auth_user where id = %s""", [1])
            row = cursor.fetchone()
        - 原生SQL语句
            - raw
                result = models.UserInfo.objects.raw('select * from userinfo')
            
    删
        models.UserGroup.objects.filter(id=2).delete()    # 注意有外键的情况
    更新
        models.UserGroup.objects.filter(id=2).update(title='公关部')
        from django.db.models import F
        # F 用来获取原来的值
        models.UserInfo.objects.all().update(age = F('age') +1)
        
    反向:别名,不用小写表名做反向操作,而是用别名.all()取数据。
    related_name = 'xxx'
        user_set ==> xxx
    related_query_name = 'xxx'
        user_set ==> xxx_set

 

# CBV

path('login.html',views.Login.as_view()),

from django.views import View
class Login(View):    
    def get(self,request):
        return HttpResponse('Login.get')
View Code

 

xss攻击 CSRF

        
xss攻击
        - 慎用 safe和mark_safe
        前端:{{ item|safe }}     
        后端:from django.utils.safestring import mark_safe
                tag = mark_safe(tag)
        - 非要用,一定要过滤关键字

CSRF
    a. 基本应用
        form表单中添加
        {% csrf_token %}
    
    b. 全站禁用
        # 'django.middleware.csrf.CsrfViewMiddleware',
    
    c. 局部禁用
        'django.middleware.csrf.CsrfViewMiddleware',
        
        from django.views.decorators.csrf import csrf_exempt

        @csrf_exempt
        def csrf1(request):

            if request.method == 'GET':
                return render(request,'csrf1.html')
            else:
                return HttpResponse('ok')
    d. 局部使用
        # 'django.middleware.csrf.CsrfViewMiddleware',
        
        from django.views.decorators.csrf import csrf_exempt,csrf_protect

        @csrf_protect
        def csrf1(request):

            if request.method == 'GET':
                return render(request,'csrf1.html')
            else:
                return HttpResponse('ok')
    
    c. 特殊CBV
            from django.views import View
            from django.utils.decorators import method_decorator
            
            @method_decorator(csrf_protect,name='dispatch')
            class Foo(View):
                
                def get(self,request):
                    pass

                def post(self,request):
                    pass
    
View Code

 

PS:CBV中添加装饰器

def wrapper(func):
            def inner(*args,**kwargs):
                return func(*args,**kwargs)
            return inner
        # 1. 指定方法上添加装饰器

            # class Foo(View):
            #
            #     @method_decorator(wrapper)
            #     def get(self,request):
            #         pass
            #
            #     def post(self,request):
            #         pass
        # 2. 在类上添加
            #     @method_decorator(wrapper,name='dispatch')
            #     class Foo(View):
            #
            #         def get(self,request):
            #             pass
            #
            #         def post(self,request):
            #             pass
            
View Code

 

Ajax提交数据时候,携带CSRF

a. 放置在data中携带
    
        <form method="POST" action="/csrf1.html">
            {% csrf_token %}
            <input id="user" type="text" name="user" />
            <input type="submit" value="提交"/>
            <a onclick="submitForm();">Ajax提交</a>
        </form>
        <script src="/static/jquery-1.12.4.js"></script>
        <script>
            function submitForm(){
                var csrf = $('input[name="csrfmiddlewaretoken"]').val();
                var user = $('#user').val();
                $.ajax({
                    url: '/csrf1.html',
                    type: 'POST',
                    data: { "user":user,'csrfmiddlewaretoken': csrf},
                    success:function(arg){
                        console.log(arg);
                    }
                })
            }

        </script>
        
    b. 放在请求头中
    
            <form method="POST" action="/csrf1.html">
                {% csrf_token %}
                <input id="user" type="text" name="user" />
                <input type="submit" value="提交"/>
                <a onclick="submitForm();">Ajax提交</a>
            </form>
            <script src="/static/jquery-1.12.4.js"></script>
            <script src="/static/jquery.cookie.js"></script>

            <script>
                function submitForm(){
                    var token = $.cookie('csrftoken');
                    var user = $('#user').val();
                    $.ajax({
                        url: '/csrf1.html',
                        type: 'POST',
                        headers:{'X-CSRFToken': token},
                        data: { "user":user},
                        success:function(arg){
                            console.log(arg);
                        }
                    })
                }
            </script>
View Code

 

 

模板

# 如果传入函数名,将会自动执行函数并取到值。
    {% for a in page_info.pager %}
        {{ a|safe }}            #xss攻击
    {% endfor %}
    
index.html

<select name="class_id">
    <!-- 循环所有的班级 -->
    {% for row in class_list %}
        <!-- 如果是当前学生所在班级,则默认选中 -->
        {% if row.id == current_student_info.class_id %}
            <option selected value="{{ row.id }}">{{ row.title }}</option>
        {% else %}
            <option value="{{ row.id }}">{{ row.title }}</option>
        {% endif %}
    {% endfor %}
</select>


{% for item in item_list %}  <a>{{ item }}</a>  {% endfor %}
  {{forloop.counter}}
  {{forloop.first}}
  {{forloop.last}}
{% if ordered_warranty %}  {% else %} {% endif %}


result = {}
for row in teacher_list:
    tid =row['tid']
    if tid in result:
        result[tid]['titles'].append(row['title'])
    else:
        result[tid] = {'tid': row['tid'],'name':row['name'],'titles': [row['title'],]}
return render(request,'teacher.html',{'teacher_list':result.values()})


母版:
    <html>
        ...
        {% block s1 %} {%endblock%}
        ...
        {% block s2 %} {%endblock%}
    
    </html>
    
子板:
    {% extends "layout.html "%}
    
    {% block s1 %} <h1>fff</h1> {%endblock%}
    {% block s2 %} <h1>ffffff</h1> {%endblock%}

layout.html
    {% block x1 %}{%endblock%}
    <h1>ff</h1>
    {% block x2 %}{%endblock%}
    <h1>2</h1>...
    {% block x3 %}{%endblock%}
index.html
    {%extends 'layout'%}
    
    {% block x1 %}dfssssssdfsd{%endblock%}
    
    {% block x2 %}dfsdfsd{%endblock%}
    
    {% block x3 %}fff{%endblock%}
    
自定义模板语言函数
创建templatetags目录,在其下创建xxx.py文件
使用特殊方法要先导入:{% load xx %}
xxx.py
from django import template
register = template.Library()

@register.filter                    # 只能有2个参数
def my_func(value,arg):
    return value+arg
        {{ name|my_func:"666"}}    # 冒号后不能有空格
        {%if name |my_func%}
        〈h3〉真〈/h3〉
        {%else%}
        〈h3〉假</h3〉
        {%endif%}
    
#register.simple_tag                # 可传多个参数
def my_func(value,a1,a2,a3):
    return value+a1+a2+a3
        {% my_func "a11" "a222" "a333"  %}
    
小组件,可在页面多次加载,可不用{% load xx %}导入
    {% include 'pub.html' %}
            pub.html
            <div>
                <h3>特别漂亮的组件</h3>
                <div class="title">标题:{{ name}}</div>
                <div class="content">内容:{{ name}}</div>
            </div>
            index.html
            <body>{% include 'pub.html' %}
View Code

 

cookie session

Cookie
    a. 保存在客户端浏览器上的“键值对”
    b. 服务端可以向用户浏览器端写cookie
    c. 客户端每次方请求时,会携带cookie去

set_cookie
    key, 
    value='', 
    max_age=None, 
    expires=None, 
    path='/',
    domain=None, 
    secure=False,         Https
    httponly=False        只能自Http请求中传入,js代码无法获取到

cookie签名:
    obj = HttpResponse('...')
    obj.set_cookie('k1','v1')
    request.COOKIES.get('k1')
    
    obj.set_signed_cookie(k1,v1,max_age,salt='ff')
    request.get_signed_cookie('k1',salt='ff')    

 
session保持会话
    Cookie是什么?
        保存在客户端浏览器上的键值对
    Session是什么?
        保存在服务端的数据(本质是键值对)
        应用:依赖cookie
        作用:保持会话(Web网站)
        
    # 登陆成功返回时,在request中设置session键值对后,将通过cookie发送随机字符串
    # session值保存在数据库表中的
    # 在浏览器请求时,获取浏览器带来的session随机字符串,随后检测是否有这个用户登录
        
    if 登陆成功:
        request.session['username']='name1'
        request.session['password']='pwd1'
        return render()
    判断是否登陆
        v = request.session.get('username')
        if v:return HttpResponse('%s,登陆成功'%v)
View Code

 

posted @ 2018-10-14 10:42  ming-yuan  阅读(242)  评论(0编辑  收藏  举报