Django基本使用

Posted 123why

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django基本使用相关的知识,希望对你有一定的参考价值。

创建Django的最基本流程(在pycharm)
    (在命令行创建项目 django-admin startproject mysite)
    1.创建app
        python manage.py startapp app01   
    2.添加app到settings文件
        pycharm默认添加      app01.apps.App01Config,
        INSTALLED_APPS = [
            django.contrib.admin,
            django.contrib.auth,
            django.contrib.contenttypes,
            django.contrib.sessions,
            django.contrib.messages,
            django.contrib.staticfiles,
            app01.apps.App01Config,
        ]
    3.配置静态文件
        STATICFILES_DIRS = (
            os.path.join(BASE_DIR,"static")
        )
        在app文件夹中添加static文件夹
(在命令行)

  django-admin startproject mysite  # 创建django项目

  python manage.py startapp app1    # 创建app

  python manage.py runserver 127.0.0.1:8080   # 运行项目


Django请求生命周期

    客户端请求服务端时,会向服务端发送有字符串组成的请求
    这个请求包含
       - 请求头
        Request URL: https://www.cnblogs.com/
        Request Method: GET
        Status Code: 200 
        Remote Address: 114.55.187.58:443
        Referrer Policy: no-referrer-when-downgrade
        
        :authority: www.cnblogs.com
        :method: GET
        :path: /
        :scheme: https
        accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
        accept-encoding: gzip, deflate, br
        accept-language: zh-CN,zh;q=0.9
        cache-control: max-age=0
        cookie: _ga=GA1.2.226328555.1568952902; __gads=ID=a7059762e3dc1aef:T=1568952901:S=ALNI_MYJ2gz_V2_CparYQryZQ6svvmFAog; _gid=GA1.2.1251713082.1570801454; _gat=1
        sec-fetch-mode: navigate
        sec-fetch-site: none
        sec-fetch-user: ?1
        upgrade-insecure-requests: 1
        user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36
       
       - 

   请求头和请求体之间由两个换行分隔
       - 请求体
         请求体就是网页内容
         
    同理服务端的响应也是一连串的字符串,也分为响应头响应体
         函数的return 就是响应  给响应赋一个变量,然后可以直接为变量以添加字典的形式添加响应头
                 send = HttpResponse("CBV_POST")
                 send["v1"] = "s1"
                 return send
         此时的响应头中就包含了一组键值对"v1":"s1"    ,像添加cookie也时这样   send.set_cookie("v2","s2")
            Content-Length: 8
            Content-Type: text/html; charset=utf-8
            Date: Sat, 12 Oct 2019 11:55:52 GMT
            Server: WSGIServer/0.2 CPython/3.7.3
            v1: s1                                     # 被添加响应体
            X-Frame-Options: SAMEORIGIN
cookie和session
    COOKIE:
        当在某站点登陆后,复制进入的页面url,然后再次在同一浏览器访问该链接,依然有效,但是在其他浏览器后设备
        访问,返回的内容是未登录的内容,这是由Cookie实现的
        Cookie:是一张身份证,它保存在客户端的某个文件中,信息由键值对构成,请求网站时会会自动发送,站点根据其中的某些信息,对用户进行身份判定
        如是否已经登录过
        
        cookie可以解决重复登录的问题,但是安全性差,所以一般使用cookie和sesion配合使用
    session:
        报错:no such table: django_session  因为sesion信息存储在数据库中,所以要先创建数据库
FBV 和CBV
    function base views   class base views
    路由分发时,对用户请求的url进行匹配(从上到下,一旦匹配不在向下继续),匹配成功则执行对应函数(FBV)
    或者类(CBV)

        CBV
            urlpatterns = [
                path(admin/, admin.site.urls),
                path(login/, views.login),
                path(index/, views.index),
                path(CBV/, views.CBV.as_view()),           # 调用as_view()方法
            ]

        from django.views import View
        class CBV(View):
            def get(self,request):                       # GET请求
                return HttpResponse("CBV_GET")
            def post(self,request):                      # POST请求
                return HttpResponse("CBV_POST")      
分页组件
    select * from table_name offset 50 limt 10    # 从第50个元素开始取,取10个  
    - Django内置分页
     from django.core.paginator import Paginator,PageNotAnInteger,EmptyPage
        - PageNotAnInteger :输入的页码不是整数
        - EmptyPage :空页码
        
        - 两个对象
            -paginator
                -创建paginator对象 paginator = Paginator(USER_LIST,10)  (要分页所有数据,每页数据数)
                    -per_page:每页显示条目数量
                    -count: 数据总个数
                    -num_pages:总页数
                    -page_range:总页数索引范围
                    -page:page对象
            -page
                -创建page对象 posts = paginator.page(要显示的那一页页码)
                    -has_next:是否有下一页
                    -next_page_number:下一页页码
                    -has_previous:是否有上一页
                    -previous_page_number:上一页页码
                    -object_list:切片后的数据列表
                    -number :当前页
                    -paginator: paginator对象
    - 扩展内置分页
    - 自定义分页   
django 数据序列化
    -javascript
        JSON.parse(ret)  字符串转换字典
        JSON.stringify() 字典转字符串
    -在django
        对于从数据库取出的数据    .values("字段名",......)或者.value_list()需要对这样的数据进行list()
        def serialize(request):
            return render(request,"serialize.html")

        from django.core import serializers
        def get_data(request):
            msg = {"status":True,"m":None}
            data = models.Student.objects.all()
            try:
                v = serializers.serialize("json",data)              
                # 只能用这个方法序列化queryset对象,像数组,字典,元组可以直接使用json.dumps()
                msg["m"] = v
            except Exception as e:
                v = e
                msg["status"] = False
                msg["m"] = v
            return HttpResponse(json.dumps(msg))
            
                $(function () {
                    serialize()
                });
                function serialize() {
                    //alert(666);
                    $.ajax({
                        url:"/get_data/",
                        type:"POST",
                        //datatype:"JSON",
                        success:function (art) {
                            var v = JSON.parse(art);
                            console.log(JSON.parse(v.m)[0].fields.username);
                            console.log(JSON.parse(v.m)[0].fields.email);
                            var tr = document.createElement("tr");
                            var td = document.createElement("td");
                            td.innerHTML = JSON.parse(v.m)[0].fields.username;
                            tr.append(td);                # 这是JS的方法
                            $("#tb").append(tr);   # 这是jquery的方法,必须找到代码中存在的标签
                        }
                    })
                }
form组件

    -用户登录信息验证
        -导入模块
            from django.forms import fields
            from django import forms
        -创建类
        class User_Msg(forms.Form):
            user = fields.CharField(max_length=32,min_length=18,required=True)    # requried = True 不能为空
            age = fields.IntegerField(required=True)
            email = fields.EmailField(required=True)
            
                -属性 widgets
                    widget=widgets.Select(choices=((1,"小明"),(2,"小红")))     # .HTML插件    (attrs = {"name":"c1"})为标签添加属性
                        -下拉框
                            # 单选下拉框
                            ff1 = fields.CharField(
                                widget=widgets.Select(choices=((1,"小明"),(2,"小红")))
                            )
                            ff2 = fields.ChoiceField(
                                choices=[(1,"小明"),(2,"小红")]
                            )
                            # 多选下拉框
                            ff3 = fields.MultipleChoiceField(
                                choices=[(1,"小明"),(2,"小红")],
                                widget = widgets.SelectMultiple()
                            )
                        -checkbox
                                # 单选checkbox
                                ff4 = fields.CharField(
                                    widget=widgets.CheckboxInput(),
                                    label="同意"
                                )
                                #多选checkbox
                                ff5 = fields.MultipleChoiceField(
                                    initial=[1,2],                                                                                               # 默认选中
                                    choices=((1,"xiaoming"),(2,"xiaohong"),(3,"xiaogong")),
                                    widget=widgets.CheckboxSelectMultiple(),
                                )
                        -radio
                            # radio  互斥
                            ff6 = fields.ChoiceField(
                                choices=[(1,"北京"),(2,"上海"),(3,"广州")],
                                initial=[1,],
                                widget=widgets.Radioselect()
                            )
                            
                        - 数据源的实时更新,上面的数据源都是自定义无法实时改变的,怎么在数据库去数据源?数据库数据改变,数据源怎么实时改变?
                            ff7 = fields.ChoiceField(
                                widget = widgets.Select()
                            )                         # 不能在静态属性中直接从数据库获取属性,因为类中静态属性在类加载完成之后就被固定,不会改变,
                                                       # 所以从数据库中取出的数据永远是第一次取出来的
                            def __init__(self,*args,**kwargs):
                                super(Form_type,self).__init__(*args,**kwargs)
                                self.fields["ff7"].widget.choices = models.Userform.objects.all().values_list("id","username")
                            """
                self.fields取出所有静态属性,因为每次刷新都会重新创建实例,也就可以在数据库重新取数据赋值给choices
              """
                        -  # 实时更新数据源的另一种实现方法,不推荐,显示的是objects对象,需要在models中增加 def __str__(self):return self.要显示的字段
                                 ff8 = ModelChoiceField(
                                    queryset=models.Userform.objects.all(),
                                    empty_label="请选择",
                                    to_field_name="id",             #value的值
                                )

                        #################### choices = 列表和元组,选项必须是元组
                    
                -属性error_messages{"invalid":....,"required":"不能为空"}
        -获取类返回的信息
            if obj.is_valid():                                            # 输入是否有效
                print("success",obj.cleaned_data)         # 验证成功的数据,返回一个字典
            else:
                print("errors",obj.errors)                       # 错误信息
        -自动生成HTML代码
            -创建一个实例obj = User_Msg(),但不传入数据,在HTML文件中{{obj.user}}
        
        - 自定义正则表达式
            -a
                from django.core.validators import RegexValidator

                class Form_re(forms.Form):
                    r1 = fields.CharField(
                        error_messages={"invalid":"...."},
                        validators=[RegexValidator(r^[0-9]+$,请输入数字),RegexValidator(r159[0-9]+&,数字必须以159开头)]
                    )
             -b
                 r2 = fields.RegexField(r^[0-9]+$,error_messages={"invalid":"..."})  #只能填入一个正则表达式
         -Ajax 基于源码的 .errors 自定制  添加新的验证(非正则表达式)
            -        
            self._clean_fields()   -> clean_字段名   对单个字段进行验证        return cleaned_data["字段名"]
            self._clean_form()       ->  clean               对全部字段进行验证        return cleaned_data
            self._post_clean()
         
         
                from django.core.exceptions import ValidationError
                class Form_Ajax(forms.Form):
                    username = fields.CharField()
                    email = fields.EmailField()
                    # 自定义方法clean_ + 字段名
                    # 正确 return self.cleaned_data["字段名"]
                    # 错误 raise ValidationError("用户名错误")
                    def clean_username(self):
                        v = self.cleaned_data["username"]
                        print(v)
                        if models.Student.objects.filter(username = self.cleaned_data["username"]).count():
                            raise ValidationError("用户名已存在")
                        else:
                            return self.cleaned_data["username"]
                    def clean_email(self):
                        return self.cleaned_data["email"]
        
        ModelForm:form与表关联
        from django import forms
        class model_form(forms.ModelForm):
            class Meta:
                model = models.User
                fields = "__all__"     # 修改所有字段    修改部分["字段一","字段二"]
        创建实例
            user_form= model_form()
            将user_form传至前端
     去掉浏览器自带的错误信息   novalidate
     
     后端发送给前端的字符串,默认不渲染,使它渲染的两种方式
        -   |safe
        -   import django.utils.safestring import mark_safe
             mark_safe("要渲染的字符串")

             
         zip函数:分离列表中元组的元素,组成新的元组
         l = [(1,2),(3,4),(5,6)]
         >>> list(zip(*l))
        [(1, 3, 5), (2, 4, 6)]       
         window.localtion.reload()  刷新页面          
Ajax
         Ajax 即“Asynchronous Javascript And XML”(异步 JavaScript 和 XML),是指一种创建交互式网页应用的网页开发技术。
        Ajax = 异步 JavaScript 和 XML 或者是 HTML(标准通用标记语言的子集)。
        Ajax 是一种用于创建快速动态网页的技术。
        Ajax 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
        通过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新。
        这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
        传统的网页(不使用 Ajax)如果需要更新内容,必须重载整个网页页面。
         $.ajax(
            {
                url:"",
                type:"POST",
                data:{},
                success: function ():{
                
                }
            }
         )
         $.ajax(
            {
                url:"",
                type:"POST",
                data:{},
                datatype:"JSON"   服务端发送的数据进行JSON转换
                success: function ():{
                
                }
            }
         )
                  $.ajax(
            {
                url:"",
                type:"POST",
                data:{},
                datatype:"JSON","TEXT","HTML","XML"   服务端发送的数据进行JSON转换
                traditional:true,  当需要发送数组数据时使用
                success: function ():{
                
                }
                error:function (){
                    数据因网络等原因未能成功发送,触发该回调函数
                }
            }
         )
         Ajax发送数据的几种情况
             a. 字符串和数字
                直接发送
             b. 数组
                添加traditional:true,
             c.  字典
                默认情况下字典不能传送,但可以先将其转换为字符串
                data:{"k1":JSON.stringify({"k1":12,"k2":13})},
         form表单中的数据可以使用一个方法直接全部获取
        data = $("#fm").serialize()
        $.ajax({
            url:"",
            data:data,
        })
                

  不刷新页面添加学生,新添加的学生操作没有绑定事件
  使用事件委托,点击操作时绑定事件,而不是在循环遍历中绑定
  事件委托:
  django 3.x
  $(要绑定事件标签的上级标签).on("click","要绑定事件的标签",function (){})
  django 1.x 2.x 
    $(要绑定事件标签的上级标签).on("要绑定事件的标签","click",function (){})
    
    find 用法
        var text = $(select[name="cls_id"]).find(option[value="+ postData.cls_id +"]).text();
        
        checked属性需要用prop获取
        prop() 方法设置或返回被选元素的属性和值。

    当该方法用于返回属性值时,则返回第一个匹配元素的值。

    当该方法用于设置属性值时,则为匹配元素集合设置一个或多个属性/值对。

    注意:prop() 方法应该用于检索属性值,例如 DOM 属性(如 selectedIndex, tagName, nodeName, nodeType, ownerDocument, defaultChecked, 和 defaultSelected)。

    提示:如需检索 HTML 属性,请使用 attr() 方法代替。

    提示:如需移除属性,请使用 removeProp() 方法。

    {{}}   如果想使用这样的字符串,可以使用    转义
        
        三种方法

    1.在js的function外定义一个变量

    var name=测试;

    function XX(){

           alert(name);

    }

    2.不使用var,直接给定义变量,隐式的声明了全局变量

    name=测试;

    function XX(){

    alert(name);

    }

    这种方法,即使该变量是在一个function内,当该function被执行后它变成了全局变量 ---- 但是function不执行它就不被其他function知道,所以最好定义在function外

    3.使用window.变量名定义为全局变量,但是注意:调用时候建议写上window.变量名,当然也可以不写;我们常用的document.getXXX的document对象就是window的

    window.name=测试;

    function XX(){

    alert(window.name);

    }
跨站请求  JSONP
    -因为同源策略的机制,浏览器会阻止另一个源返回给本源的文档,其实请求和响应都进行了,只是浏览器不接受,我们无法获得响应
        这个策略只会制约XMLHttpResponse的跨站请求,有些标签不受制约,如img,script
        JSONP就是利用script标签不受制约的特性,进行跨站请求的
            function req() {
                $.ajax({
                    url:"http://127.0.0.1:8080/index/",
                    type:"GET",                                                        # 请求方式只能是GET,就算修改为POST也会自动改回来
                    dataType:"JSONP",
                    jsonp:"callback",                                   # 修改包裹数据的函数名
                    jsonCallback:"foo1",
                    success:function (arg) {
                        console.log(arg)
                    }

                })
            }
                 function foo1(arg) {         #返回的数据必须以一个函数参数的形式返回,
                     console.log(arg)           #即函数名(数据)这样函数会被请求端执行,数据作为参数被接收了
                 }
         -JSONP原理:
                    function submitJsonp2() {
                        var tag = document.createElement(script);
                        tag.src = http://127.0.0.1:9000/xiaokai.html;
                        document.head.appendChild(tag);
                        document.head.removeChild(tag);
                    }

                    function fuck(arg) {
                        $(#content).html(arg);
                    }   
全局变量的优点:

    可以减少变量的个数,减少由于实际参数和形式参数的数据传递带来的时间消耗。

    全局变量的缺点:
    (1)全局变量保存在静态存贮区,程序开始运行时为其分配内存,程序结束释放该内存。与局部变量的动态分配、动态释放相比,生存期比较长,因此过多的全局变量会占用较多的内存单元。
    (2)全局变量破坏了函数的封装性能。函数象一个黑匣子,一般是通过函数参数和返回值进行输入输出,函数内部实现相对独立。但函数中如果使用了全局变量,那么函数体内的语句就可以绕过函数参数和返回值进行存取,这种情况破坏了函数的独立性,使函数对全局变量产生依赖。同时,也降低了该函数的可移植性。
    (3)全局变量使函数的代码可读性降低。由于多个函数都可能使用全局变量,函数执行时全局变量的值可能随时发生变化,对于程序的查错和调试都非常不利。
    因此,如果不是万不得已,最好不要使用全局变量。
XSS攻击:跨站脚本攻击

    用户在网页上进行如评论之类的输入,评论的是一段脚本代码,如果后端认为是安全的,就会渲染在页面上,
    造成其他浏览该评论的用户被脚本攻击
- 文件上传
    -普通上传,选择文件的标签样式无法修改
    -NB上传,将标签透明,用其他标签盖住
    -基于form上传
    -基于Ajax上传

    -form表单包含 enctype:"mutipart/form-data"
    - input标签选择 type:"file"

    -前端使用img = request.FILES.get("name属性名")
        -img.chunks()获取内容,这是一个迭代器
        -img.name   获取文件名
        -img.size   获取文件大小
        
        
        urls.py中使用正则表达式
        from django.urls import path,re_path
        re_path(rindex/(?P<de_id>d+).html,views.index_get,name = "index_all")   #  注意d+  反斜杠
         name是别名通过别名在views.py和html中都可以反向生成url
         在views.py中
             from django.urls import reverse
             对于有分组名的url
             current_path = reverse("name",kwargs = {"分组名":参数})
             没有的
             current_path = reverse("name",args = (参数1,参数2......))
         在html中
             {% url "name"  分组名 = 参数%} 或者没有分组名的时候直接写参数          
权限管理
    基于角色的访问控制(RBAC)Role Bases Access Control
登录验证
    from django.shortcuts import render,redirect
    from django.contrib.auth import authenticate,login,logout            # 导入模块

    def acc_login(request):
        if request.method == "GET":
            return render(request, "login.html")
        else:
            username = request.POST.get("username")
            password = request.POST.get("password")
            user = authenticate(username=username,password=password)     #进行验证,返回的是一个对象
            if user:
                login(request,user)                                                                         # 验证成功并不是登陆成功,要写入session
                url = request.GET.get("next",default="/crm/")
                print(url)
                return redirect(".."+url)
            return render(request,"login.html")
    def acc_logout(request):                                                                            # 清除session
        logout(request)
        return redirect("/login/")

    # 未登录,不显示首页
    # 会访问 http://127.0.0.1:8000/accounts/login/?next=/crm/ 
    # 在配置文件中修改LOGIN_URL = ‘../login/‘,?next=/crm/ 是登录成功要跳转的页面
    from django.contrib.auth.decorators import login_required
    @login_required()
    def dashbase(request):
        return render(request,"crm/home_page.html")
定制模板中使用的函数
    -创建一个包  Python Package  
    -创建一个python文件   kingadmin_test.py

    -kingadmin_test.py
         from django.utils.template import Library
        
         register = Library()
         @register.simple_tag
         def bulid_ele(a,b):
             return a+b
    -在模板中使用,先load   .py文件  {% load kingadmin_test %}
    -使用  {%  bulid_ele a b %}
SSO single sign on 单点登录
    多套系统使用同一套账户,这个账户由单点也就是另一套系统维护,当多套系统登陆时,都会到这个单点进行验证,根据单点返回的结果
    判断是否登陆成功,常用的有LDAP(轻型目录访问协议
                                                                (英文:Lightweight Directory Access Protocol,缩写:LDAP,/??ldæp/)
                                                                    是一个开放的,中立的,工业标准的应用协议,
                                                                    通过IP协议提供访问控制和维护分布式信息的目录信息。)

 

以上是关于Django基本使用的主要内容,如果未能解决你的问题,请参考以下文章

Django rest_framewok框架的基本组件

django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE的解决办法(转)(代码片段

django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE的解决办法(转)(代码片段

使用 Django 模板作为片段

如何在 Django 中显式重置模板片段缓存?

html PHP代码片段: - AJAX基本示例:此代码演示了使用PHP和JavaScript实现的基本AJAX功能。