• day17-Django进阶及orm


    day17 2018-08-12 
    
    Django框架02
    
    1. 今日内容:
        1. 新建Django项目梳理
            1. 模板文件路径配置
            2. 数据库配置
            3. 静态文件配置
            4. 注释掉csrf中间件那一行
        2. Django默认sqlite3数据库的简单用法
        
        3. 路由系统进阶:https://www.cnblogs.com/liwenzhou/articles/8271147.html
            - 动态路由
            urls.py中通过正则表达式的分组匹配,捕获用户访问的url中的值,传递给视图函数
            分组匹配:
                相当于给视图函数传递 位置参数
            分组命名匹配:
                相当于给视图函数传递 关键字参数
            
            - name
                防止将url硬编码到我们的业务逻辑代码中,给url起别名
                通过别名,反向找到 url
                在views.py中:
                    from django.urls import reverse
                    具体的url = reverse('url别名')
                        
        4. 视图函数进阶:https://www.cnblogs.com/liwenzhou/articles/8305104.html
            1. views.py
                1. 基础必会三件套
                    1. HttpResponse('字符串')
                    2. render(request, "xx.html", {"key": value})
                    3. redirect("/其它的url/")
                2. FBV(Function Base View) 基于函数的视图
                    通过request.method == "POST" 去判断
                    
                3. CBV(Class Base View)    基于类的视图
                    1. 必须继承views.View     --> from django import views
                    2. 写一个自己的视图类
                    3. 通过定义不同的方法,来处理用户不同的请求
                    4. 在urls.py中注册视图的时候要写 views.类名.as_view()
            2. request对象的常用属性和方法
                request表示的是和用户请求相关的所有数据
                1. request.method       --> 用户当前请求的请求方法
                2. request.GET          --> 用户请求中url中的参数
                3. request.POST         --> 用户POST请求的数据
                4. request.path_info    --> 用户访问的url路径是什么
                
            3. Django上传文件
                1. 前端页面
                    1. form表单一定要有action,method必须是post
                    2. 一定要配置enctype="multipart/form-data
                2. 后端:
                     def post(self, request):
                        # 拿到用户发送的文件数据
                        file_obj = request.FILES.get("code")
                        # 保存下来
                        # 1. 拿到用户上传的文件名
                        filename = file_obj.name
                        # 2. 在服务端创建一个同名的文件
                        with open(filename, "wb") as f:
                            # 3. 从用户上传的文件对象中一点一点读数据,往我本地创建的文件句柄里一点一点写
                            for i in file_obj.chunks():
                                f.write(i)
                        return HttpResponse("上传成功!")
            
            4. JsonResponse
                专门用来返回JSON格式数据的响应对象
                from django.http import JsonResponse
                
         5. 模板引擎进阶:https://www.cnblogs.com/liwenzhou/p/7931828.html
            1. 已经学过的Django模板语言的语法
                1. 两个语法:
                    1. {{ }}    --> 跟变量相关的操作
                    2. {% %}    --> 跟逻辑相关的操作
                2. 变量相关
                    1. 传字典或对象类型的数据     obj.name/obj.age
                    2. 传数组类型的数据           obj.索引值
                3. 日期格式化
                    <p>{{ today|date:"Y-m-d H:i:s"}}</p>
                4. 显示真正的html代码
                    <p>{{ link|safe }}</p>
            2. 母板
                1. 为什么要用母版?
                    不同的页面有大量重复的代码,我们可以把公用的部分提取出来放在单独一个文件
                2. 怎么使用?
                    1. 在子页面 通过使用 {% extends ‘模板名’ %}   --> 放在子页面的最上面
                    2. {% block xx %}{% endblock %}
            3. 组件
                把单独的一段html代码放在一个文件
                使用 {% include '组件名' %}导入
                
        6. CSRF
            1. 为什么要有csrf_token?
            2. Django中如何使用?
                在render的页面上写上{% csrf_token %}
            3. 如果是form表单形式提交,必须放在form表单中    
                
                
        7. ORM单表查询13条+外键操作(一对多):
            1. ORM上周知识点:
                1. 查询
                    1. 查所有
                        models.Publisher.objects.all()
                    2. 查某个具体的记录
                        models.Publisher.objects.get(id=1)   --> 注意查询条件不成立就报错
                2. 删除一条记录
                    models.Publisher.objects.get(id=1).delete()
                3. 创建一条记录
                    models.Publisher.objects.create(name="新出版社名字", addr="出版社地址") 
                4. 修改一条记录
                    obj = models.Publisher.objects.get(id=1)
                    obj.name = "新名字"
                    obj.save()
                
    
            2. 字段和参数:  https://www.cnblogs.com/liwenzhou/p/8688919.html
                1. 上周字段和参数:
                    1. models.AutoField(primary_key=True)
                    2. models.CharField(max_length=32)
                    
                2.     常用字段和参数
                    1. 字段
                        1. CharField
                        2. AutoField
                        3. DateField
                        
                        4. DateTimeField()
                        5. IntergeField()
                    2. 参数
                        1. null=True
                        2. default=默认值
                        3. unique=True
                        4. 时间字段
                            1. auto_now_add=True    第一次创建时
                            2. auto_add=True        每次更新时
                
                3. ORM必知必会单表查询13条
                    1. all()                             --> 查询所有结果
                    2. filter()                          --> 根据查询条件查询数据库的
                    3. get()                             --> 获取一个唯一的值
                    4. exclude()                         --> 将符合条件的都剔除掉,留下不符合条件的
                    5. values('字段名', ...)             --> 返回一个QuerySet,里面是字典
                    6. values_list(字段名', ...)         --> 返回一个QuerySet,里面是元祖
                    7. order_by()                        --> 对查询结果排序
                    8. reverse()                         --> 对一个有序的查询结果集做反转
                    9. distinct()                        --> 去重,跨表查询时去掉重复的记录,MySQL不支持按字段去重
                    10. count()                          --> 返回数据条数
                    11. first()                          --> 取第一个数据
                    12. last()                           --> 取最后一条数据
                    13. exists()                         --> 判断表里有没有数据
                    
                    
                    分类:
                        1. 返回QuerySet列表的有哪一些?
                            1. all()
                            2. filter()
                            3. exclude()
                            4. order_by()
                            5. reverse()
                            6. distinct()
                            
                            7. values('字段名', ...)     --> 查询结果的列表里,都是字典
                            8. values_list(字段名', ...) --> 查询结果的列表里,都是元祖
                            
                        2. 返回具体对象的
                            1. first()
                            2. last()
                            3. get()
                            
                        3. 返回数字的
                            1. count()
                        4. 返回布尔值
                            1. exists()
                    
                4. 单表查询神奇的双下划线
                    查询操作:https://www.cnblogs.com/liwenzhou/p/8660826.html
                    
                    1. 外键 ForeignKey 
                        通过Foreignkey字段 ,能够得到和我关联的那个对象
                        数据库中保存的字段名是 外键字段_id
                    2. 外键增删改查
                    3. 跨表查询
                        1. 基于对象的查询
                            1. 正向查
                            2. 反向查
                        2. 基于QuerySet的查询
                            1. 正向查
                            2. 反向查
                        
                        
        8. cookie&session:https://www.cnblogs.com/liwenzhou/p/8343243.html
            1. Cookie
                1. 是什么?
                    保存在浏览器端的键值对!
                    服务端在返回响应的时候,告诉浏览器保存的键值对!浏览器可以拒绝保存Cookie.
                    
                2. 为什么要有cookie?
                    HTTP请求是无状态的,我们需要保存状态  --> cookie 
                    
                3. Django中cookie的使用
                    1. 设置cookie
                        rep = HttpResponse("ok")
                        rep.set_cookie("key", "value", max_age=xx秒)
                        rep.set_signed_cookie("key", "value", salt="ooxx", max_age=xx秒)
                    2. 获取cookie
                        request.COOKIES.get("key")
                        request.get_signed_cookie("key", default="", salt="ooxx")
                    3. cookie有失效时间
                        1. Django中不设置,关闭浏览器就失效了
                        2. 通过max_age设置超时时间
                        
                4. 补充3点:
                    1. 如何登陆后再跳转回之前访问的页面    --> next参数实现
                    2. 如何将FBV的装饰器应用到CBV上        --> from django.utils.decorators import method_decorator
                    3. 装饰器修复技术                      --> from functools import wraps
            
            
            2. session
                1. 保存在服务端的键值对!
                下周讲!
                
    
    2. 练习题:
        1. django请求生命周期
        2. values和values_list的区别?
        3. session和cookie是什么?以及区别?
        4. django路由系统中name的作用?
        5. filter和exclude的区别?
        6. ORM查询示例:
            表结构:
                出版社表:
                    ID   名称
                图书表:
                    ID   书名称    价格     出版社ID
            题目:
                1. 查询老男孩出版社出版过的价格大于200的书籍
                2. 查询所有以py开头的书籍名称
                3. 查询价格为50,100或者150的所有书籍名称及其出版社名称
                4. 查询价格在100到200之间的所有书籍名称及其价格
                5. 查询所有人民出版社出版的书籍的价格(从高到低排序,去重)
                6. 查询价格大于200的书籍的个数
                7. 查询价格不等于100的所有书籍
    
    
    3. 作业:主机管理【02】:主机管理
        1. 基于django创建表:
            用户表:ID、用户名、密码
            
            业务线表:ID、名称
            
            主机表:ID、主机名、密码、业务线ID
            
        2. 主机管理:增删改查(一对多,不需要做业务线管理,只要在数据库录入业务线数据即可)
        
        3. 使用母板和动态路由
        4. 套用BootStrap样式
    
        采分点:
            练习题:20
            实现所有功能:70
            代码写的清晰、健壮、可扩展:10
    课上笔记
    sqlite3文件数据库,点开即可使用
    sqlite3数据库添加时间类型 可能有问题。

    urls---views(写函数)----html

    一、路由系统
    1.Django的路由系统;用户请求与url'内容中是否匹配

    2.正则表达式

    动态匹配路由的方式传参数
    分组匹配------------^edit_publisher/(d+)/$
    url(r'^admin/', admin.site.urls),
    url(r'^publisher_list/$', views.publisher_list, name="alex"),
    url(r'^edit_publisher/(?P<edit_id>d+)/$', views.EditPublisher.as_view(), name="alex"),
    url.py
    def edit_publisher(request):
        if request.method == "POST":
            # 接收用户提交过来的数据
            edit_id = request.POST.get("id")
            new_name = request.POST.get("name888")
            # 去数据库修改出版社名字
            obj = models.Publisher.objects.get(id=edit_id)
            obj.name = new_name
            obj.save()
            return redirect("/publisher_list/")
        # 取url携带的参数
        print(request.GET.get("id"))
        edit_id = request.GET.get("id")
        # 去数据库找编辑的出版社
        publisher_obj = models.Publisher.objects.get(id=edit_id)
    
        return render(request, "edit_publisher.html", {"obj": publisher_obj})
    不使用动态路由views
    def edit_publisher(request, edit_id):
        print(reverse('alex'))
        print("=" * 120)
        if request.method == "POST":
            new_name = request.POST.get("name888")
            # 去数据库修改出版社名字
            obj = models.Publisher.objects.get(id=edit_id)
            obj.name = new_name
            obj.save()
            return redirect(reverse('alex'))
        print(edit_id)
        publisher_obj = models.Publisher.objects.get(id=edit_id)
        return render(request, "edit_publisher.html", {"obj": publisher_obj})
    分组命名匹配views-FBV
    分组命名匹配---^edit_publisher/(?P<edit_id>d+)/$

    分组匹配:
    相当于给视图函数传递 位置参数
    分组命名匹配:
    相当于给视图函数传递 关键字参数


    ?P<pk>给分组取一个名字 将捕获的值当成关键字参数传入
    修改list html中a标签编辑、删除取值路径
    reverse
    # CBV
    class EditPublisher(views.View):
        def get(self, request, edit_id):
            publisher_obj = models.Publisher.objects.get(id=edit_id)
            return render(request, "edit_publisher.html", {"obj": publisher_obj})
    
        def post(self, request, edit_id):
            new_name = request.POST.get("name888")
            # 去数据库修改出版社名字
            obj = models.Publisher.objects.get(id=edit_id)
            obj.name = new_name
            obj.save()
            return redirect(reverse('alex'))
    分组匹配的views-CBV


    二、视图函数
    1.import views 是dj中自带的函数
    cbv views.类名.as_view()

    2,dj上传文件 ,

    1. 前端页面
    1. form表单一定要有action,method必须是post
    2. 一定要配置enctype="multipart/form-data

    2.后端:chunks()不写也可实现功能,此功能是django提供的方法,一般写上。

    # Django上传文件示例
    class Upload(views.View):
        def get(self, request):
            return render(request, "upload.html")
    
        def post(self, request):
            # 拿到用户发送的文件数据
            file_obj = request.FILES.get("code")
            # 保存下来
            # 1. 拿到用户上传的文件名
            filename = file_obj.name
            # 2. 在服务端创建一个同名的文件
            with open(filename, "wb") as f:
                # 3. 从用户上传的文件对象中一点一点读数据,往我本地创建的文件句柄里一点一点写
                for i in file_obj.chunks():
                    f.write(i)
            return HttpResponse("上传成功!")
    上传文件views
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>上传文件</title>
    </head>
    <body>
    
    <form action="/upload/" method="post" enctype="multipart/form-data">
        <input type="file" name="code">
        <input type="submit" value="提交">
    </form>
    </body>
    </html>
    upload.html

    json格式的数据---类似于{‘code’:0,'data':'alex'}
    from django.http import JsonResponse
    # 返回JSON格式数据
    class JsonTest(views.View):
        def get(self, request):
            res = {"code": 0, "data": "alex"}
            res2 = ["alex", "污Sir", "金老板", "小姨妈", "MJJ"]
            # 1. 先将字典序列化成json格式的字符串
            # import json
            # s = json.dumps(res2, ensure_ascii=False) #ensure_ascii=False确保输出汉字
            # return HttpResponse(s)
            return JsonResponse(res2, safe=False)  # 列表类型要写safe=False
    返回JSON格式数据

    xss攻击(跨站脚本攻击) : js代码--死循环

    三、模板引擎

    1. {{ }} --> 跟变量相关的操作
    2. {% %} --> 跟逻辑相关的操作

    {% for teacher in data %}
            {% if forloop.last %}
                {{ teacher }}
            {% else %}
                {{ teacher }},
            {% endif %}
        {% endfor %}
    例子

    4. 显示真正的html代码
    <p>{{ link|safe }}</p>

    import datetime
    
    now = datetime.datetime.now()
    print(now, type(now))
    ret = now.strftime("%Y-%m-%d %H:%M:%S")  # 日期类型转换为字符串类型
    print(ret, type(ret))
    日期格式化

    模板语言不支持连续判断
    不支持:{#<p>{% if 3 > 2 > 1 %}{% endif %}</p>#}

    需要这样写:{#<p>{% if 3 > 2 and 2 > 1 %}{% endif %}</p>#}
    默认找属性,属性优先级大于方法
    # 测试模板语法
    def template_test(request):
        data = ["金老板", "景女神", "MJJ"]
        # data = ""
        filesize = 1234567890
        import datetime
        today = datetime.datetime.today()
        link = "<script>for(;;){alert(123)}</script>"
    
        class Person(object):
            def __init__(self, name, dream):
                self.name = name
                self.dream = dream
    
            def dream(self):
                return "我的梦想是学好Python!"
    
        pw = Person("彭玮", "不去下一期!")
    
        return render(request, "t.html", {
            "data": data,
            "file_size": filesize,
            "today": today,
            "link": link,
            "person": pw
        })
    测试模板语法
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    
    {#<p>{{ data.1 }}</p>#}
    <p>{{ data|default:"暂无数据" }}</p>
    {##管道符前后及冒号前后不要加空格#}
    <p>{{ file_size|filesizeformat }}</p>
    <p>{{ today }}</p>
    {#年月日时分秒#}
    <p>{{ today|date:"Y-m-d H:i:s"}}</p>
    
    <p>{{ link }}</p>
    {#加safe允许显示html及频繁弹出框#}
    {#<p>{{ link|safe }}</p>#}
    
    <hr>
    
    <p>
        {% for teacher in data %}
        {#        最后一次循环,不加,#}
            {% if forloop.last %}
                {{ teacher }}
            {% else %}
                {{ teacher }},
            {% endif %}
        {% endfor %}
    </p>
    {#<p>{% if 3 > 2 > 1 %}{% endif %}</p>#}
    {##}
    {#<p>{% if 3 > 2 and 2 > 1  %}{% endif %}</p>#}
    
    <hr>
    
    {{ person.name }}
    {{ person.dream }}
    
    
    </body>
    </html>
    t.html

    四、母版
    bt--css jquery--js

    怎么使用?
    1. 在子页面 通过使用 {% extends ‘模板名’ %} --> 放在子页面的最上面
    2. {% block xx %}{% endblock %}

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>{{ html_title }}</title>
        <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">
        {% block page-css %}
        
        {% endblock %}
    </head>
    <body>
    {% include 'nav.html' %}
    <div class="container">
        <div class="row">
            <div class="col-md-8 col-md-offset-2">
    
                {% block page-main %}
    
                {% endblock %}
    
            </div>
        </div>
    </div>
    <script src="/static/jquery.js"></script>
    {% block page-js %}
    
    {% endblock %}
    </body>
    </html>
    mama.html
    {% extends 'mama.html' %}
    
    {% block page-main %}
    <table class="table table-bordered">
        <thead>
        <tr>
            <th>#</th>
            <th>id</th>
            <th>出版社名称</th>
            <th>操作</th>
        </tr>
        </thead>
        <tbody>
        {% for publisher in publisher_list %}
            <tr>
                <td>{{ forloop.counter }}</td>
                <td>{{ publisher.id }}</td>
                <td>{{ publisher.name }}</td>
                <td>
                    <a href="/edit_publisher/{{ publisher.id }}/" class="btn btn-info">编辑</a>
                    <a href="/delete_publisher/" class="btn btn-danger">删除</a>
                </td>
            </tr>
        {% endfor %}
        </tbody>
    </table>
    
    {% endblock %}
    
    {#我这个页面才用到的一个js文件#}
    {% block page-js %}
        <script src="/static/1.js"></script>
    {% endblock %}
    使用母版.html

    3. 组件
    把单独的一段html代码放在一个文件
    使用 {% include '组件名' %}导入

    
    
    五.跨站请求伪造 CSRF
    网站无法限制谁给他发请求,例如:自己写的页面也可跳转到sougouweb。
    钓鱼网站 往银行发请求,获取你的用户名、密码等信息。

    value="随机的字符串"
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <form action="银行转账的api" method="post">
        <input type="text" name="key" value="adadaaljqoiqwkqkwqqqrdadq" style="display: none">
        <input type="text" name="query">
        <input type="submit" value="提交">
    </form>
    
    <hr>
    
    </body>
    </html>
    csrf.html
    def csrf_test(request):
        if request.method == "POST":
            print(request.POST)
            return HttpResponse("OK")
        return render(request, "csrf_test.html")
    csrf_test的view
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <form action="" method="post">
    {#    生成随机字符串的input框,必须在form表单里 #}
        {% csrf_token %}
        <input type="text" name="name">
        <input type="submit" value="提交">
    </form>
    </body>
    </html>
    csrf_test.html

    六、ORM单表查询13条+外键操作(一对多)

    1.字段和参数
    1. 字段
                        1. CharField
                        2. AutoField
                        3. DateField
                        
                        4. DateTimeField()
                        5. IntergeField()
                    2. 参数
                        1. null=True
                        2. default=默认值
                        3. unique=True
                        4. 时间字段
                            1. auto_now_add=True    第一次创建时
                            2. auto_add=True        每次更新时
    AutoField(Field)
            - int自增列,必须填入参数 primary_key=True
    
        BigAutoField(AutoField)
            - bigint自增列,必须填入参数 primary_key=True
    
            注:当model中如果没有自增列,则自动会创建一个列名为id的列
            from django.db import models
    
            class UserInfo(models.Model):
                # 自动创建一个列名为id的且为自增的整数列
                username = models.CharField(max_length=32)
    
            class Group(models.Model):
                # 自定义自增列
                nid = models.AutoField(primary_key=True)
                name = models.CharField(max_length=32)
    
        SmallIntegerField(IntegerField):
            - 小整数 -3276832767
    
        PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
            - 正小整数 032767
        IntegerField(Field)
            - 整数列(有符号的) -21474836482147483647
    
        PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
            - 正整数 02147483647
    
        BigIntegerField(IntegerField):
            - 长整型(有符号的) -92233720368547758089223372036854775807
    
        BooleanField(Field)
            - 布尔值类型
    
        NullBooleanField(Field):
            - 可以为空的布尔值
    
        CharField(Field)
            - 字符类型
            - 必须提供max_length参数, max_length表示字符长度
    
        TextField(Field)
            - 文本类型
    
        EmailField(CharField):
            - 字符串类型,Django Admin以及ModelForm中提供验证机制
    
        IPAddressField(Field)
            - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制
    
        GenericIPAddressField(Field)
            - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
            - 参数:
                protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
                unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启此功能,需要protocol="both"
    
        URLField(CharField)
            - 字符串类型,Django Admin以及ModelForm中提供验证 URL
    
        SlugField(CharField)
            - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)
    
        CommaSeparatedIntegerField(CharField)
            - 字符串类型,格式必须为逗号分割的数字
    
        UUIDField(Field)
            - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证
    
        FilePathField(Field)
            - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
            - 参数:
                    path,                      文件夹路径
                    match=None,                正则匹配
                    recursive=False,           递归下面的文件夹
                    allow_files=True,          允许文件
                    allow_folders=False,       允许文件夹
    
        FileField(Field)
            - 字符串,路径保存在数据库,文件上传到指定目录
            - 参数:
                upload_to = ""      上传文件的保存路径
                storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
    
        ImageField(FileField)
            - 字符串,路径保存在数据库,文件上传到指定目录
            - 参数:
                upload_to = ""      上传文件的保存路径
                storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
                width_field=None,   上传图片的高度保存的数据库字段名(字符串)
                height_field=None   上传图片的宽度保存的数据库字段名(字符串)
    
        DateTimeField(DateField)
            - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
    
        DateField(DateTimeCheckMixin, Field)
            - 日期格式      YYYY-MM-DD
    
        TimeField(DateTimeCheckMixin, Field)
            - 时间格式      HH:MM[:ss[.uuuuuu]]
    
        DurationField(Field)
            - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型
    
        FloatField(Field)
            - 浮点型
    
        DecimalField(Field)
            - 10进制小数
            - 参数:
                max_digits,小数总长度
                decimal_places,小数位长度
    
        BinaryField(Field)
            - 二进制类型
    
    字段合集
    字段合集
    以下内容参考博客地址:https://www.cnblogs.com/liwenzhou/p/8660826.html
    2.ORM必知必会单表查询13条
    1. all()                             --> 查询所有结果
                    2. filter()                          --> 根据查询条件查询数据库的
                    3. get()                             --> 获取一个唯一的值
                    4. exclude()                         --> 将符合条件的都剔除掉,留下不符合条件的
                    5. values('字段名', ...)             --> 返回一个QuerySet,里面是字典
                    6. values_list(字段名', ...)         --> 返回一个QuerySet,里面是元祖
                    7. order_by()                        --> 对查询结果排序
                    8. reverse()                         --> 对一个有序的查询结果集做反转
                    9. distinct()                        --> 去重,跨表查询时去掉重复的记录,MySQL不支持按字段去重
                    10. count()                          --> 返回数据条数
                    11. first()                          --> 取第一个数据
                    12. last()                           --> 取最后一条数据
                    13. exists()                         --> 判断表里有没有数据
    # 如何在一个py文件中 使用Django项目的相关配置或内容
    import os
    
    if __name__ == '__main__':
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")  # manage.py中第6行
        import django
    
        django.setup()
    
        from app01 import models
    
        # 查询age=18的第一个人
        # ret = models.Person.objects.get(age=18)  # pk(主键) unique
        # print(ret)
        # 查询age=18的所有人
        # ret = models.Person.objects.filter(age=18) #获取的是对象的列表,多个值
        # print(ret[0])  # ret[0]取一个值
    
        # ret = models.Person.objects.filter(age=18).values("age", "phone")
        # print(ret)  # 打印指定的两个字段,字典内容
    
        # ret = models.Person.objects.filter(age=18).values_list("age", "phone")
        # print(ret) # 打印指定的两个字段,小元组内容,只有值,无key了
    
        # 排序
        # ret = models.Person.objects.all().order_by("age")
        # print(ret)
    
    
     # 神奇的双下划线
        # 查询年龄大于18岁的
        # ret = models.Person.objects.filter(age__gt=18, id__gt=1)
        # print(ret)
    
        # 查询id值在 [1, 2]的人
        # ret = models.Person.objects.filter(id__in=[1, 2, 20000])
        # print(ret)  # 取1,2的人,不会报错
        #
        # 查询id值不在[1,2]的人
        # ret = models.Person.objects.exclude(id__in=[1,2])
        # print(ret)
    
        # 查询名字中包含 JJ 的那个人
        # ret = models.Person.objects.filter(name__contains="JJ")
        # print(ret)
        # 不区分大小写查询
        # ret = models.Person.objects.filter(name__icontains="jj")
        # print(ret)
    
        # 查询id在1-3区间内的数据
        # ret = models.Person.objects.filter(id__range=[1, 3])
        # print(ret)
    
        # 查询以JJ结尾的人
        # ret = models.Person.objects.filter(name__endswith='JJ')
        # print(ret)
        # print(models.Person.objects.first().birthday) #sqlite3中显示None,日期的格式有问题,mysql可以显示
        # 查询 生日 是 2018年的所有人
        # ret = models.Person.objects.filter(birthday__year=2018)
        # print(ret)
    
    
    #外键
        # 查询第一本书关联的出版社的名字
        # 1. 基于对象的查询
        # book_obj = models.Book.objects.first()
        # ret = book_obj.publisher.name
        # print(ret)
        # 2. 基于queryset的双下划线查询,双下划线表示跨表
        # ret = models.Book.objects.all().values_list("publisher__name").distinct()
        # print(ret)
    
        # 反向查询
        # 1. 由出版社反向查询书籍(基于对象的查询)
        # publisher_obj = models.Publisher.objects.get(id=2)  # 找到张江出版社
        # 张江出版社出版的所有书籍
        # ret = publisher_obj.book_set.all()
        # print(ret)
    
        # 2. 基于queryset的双下划线
        # 江出版社出版的所有书籍的书名
        ret = models.Publisher.objects.filter(id=2).values_list("book__title")
        print(ret)
    orm_test.py

    注:
    查询:
    1.根据唯一值查询:用get
    2.一般会用filter

    1256789 11 12 常用
    id__gt=1 #id大于1的数据
    分类:
                        1. 返回QuerySet列表的有哪一些?
                            1. all()
                            2. filter()
                            3. exclude()
                            4. order_by()
                            5. reverse()
                            6. distinct()
                            
                            7. values('字段名', ...)     --> 查询结果的列表里,都是字典
                            8. values_list(字段名', ...) --> 查询结果的列表里,都是元祖
                            
                        2. 返回具体对象的
                            1. first()
                            2. last()
                            3. get()
                            
                        3. 返回数字的
                            1. count()
                        4. 返回布尔值
                            1. exists()
    分类
    不同的对象有不同的方法,可以根据对象调用方法。返回QuerySet的使用加[0]

    3. 单表查询神奇的双下划线
    models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 获取id大于1 且 小于10的值
     
    models.Tb1.objects.filter(id__in=[11, 22, 33])   # 获取id等于11、22、33的数据
    models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in
     
    models.Tb1.objects.filter(name__contains="ven")  # 获取name字段包含"ven"的
    models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
     
    models.Tb1.objects.filter(id__range=[1, 3])      # id范围是1到3的,等价于SQL的bettwen and
     
    类似的还有:startswith,istartswith, endswith, iendswith 
    
    date字段还可以:
    models.Class.objects.filter(first_day__year=2017)

        4.外键操作--重点!

    通过Foreignkey字段 ,能够得到和我关联的那个对象,例如: book.publisher.name
    一对多--外键操作
    外键关联--查、增删、改
    关联字段__被查名称 可以跨表查询

    基于例子练习跨表查询(正向、反向),例子见上 orm_test.py或如下
    #外键
        # 查询第一本书关联的出版社的名字
        # 1. 基于对象的查询
        # book_obj = models.Book.objects.first()
        # ret = book_obj.publisher.name
        # print(ret)
        # 2. 基于queryset的双下划线查询,双下划线表示跨表
        # ret = models.Book.objects.all().values_list("publisher__name").distinct() #所有书籍出版社的名字
        # ret = models.Book.objects.filter(id=1).values_list("publisher__name")#id为1的书籍出版社的名字
        # print(ret)
    
        # 反向查询
        # 1. 由出版社反向查询书籍(基于对象的查询)
        # publisher_obj = models.Publisher.objects.get(id=2)  # 找到张江出版社
        # 张江出版社出版的所有书籍
        # ret = publisher_obj.book_set.all()
        # print(ret)
    
        # 2. 基于queryset的双下划线
        # 江出版社出版的所有书籍的书名
        ret = models.Publisher.objects.filter(id=2).values_list("book__title")
        print(ret)
    from django.db import models
    
    # Create your models here.
    
    
    class Publisher(models.Model):
        name = models.CharField(max_length=12)
    
    
    # 书籍表
    class Book(models.Model):
        title = models.CharField(max_length=32)
        publisher = models.ForeignKey(to="Publisher", on_delete=models.CASCADE) #on_delete级联删除
    
    
    class Person(models.Model):
        name = models.CharField(max_length=12, default="alex")
        age = models.IntegerField(default=18)
        birthday = models.DateField()
        birthday2 = models.DateTimeField(null=True)
        phone = models.CharField(max_length=11, unique=True)
        # 创建该记录时自动把当前时间保存到该字段
        join_date = models.DateField(auto_now_add=True)
        # 更新该记录的值时 自动把当前时间保存到该字段
        last_date = models.DateField(auto_now=True)
    
        def __str__(self):
            return "{}-{}".format(self.age, self.phone)
    models.py
    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    
    # from django.urls import path
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^publisher_list/$', views.publisher_list, name="alex"),
        url(r'^edit_publisher/(?P<edit_id>d+)/$', views.EditPublisher.as_view(), name="alex"),
        # 测试上传你文件
        url(r'^upload/$', views.Upload.as_view()),
        # 测试返回Json格式数据
        url(r'^json_test/$', views.JsonTest.as_view()),
        # 测试模板语法
        url(r'^template_test/$', views.template_test),
        # 测试跨站请求伪造 (CSRF)
        url(r'^csrf_test/$', views.csrf_test),
    
        url(r'^book_list/$', views.book_list),
        url(r'^add_book/$', views.AddBook.as_view()),
        url(r'^delete_book/(?P<pk>d+)/$', views.DeleteBook.as_view()),
        url(r'^edit_book/(?P<pk>d+)/$', views.EditBook.as_view()),
        url(r'^login/$', views.login),
    
    
    ]
    urls.py--all
    @login_check
    def book_list(request):
        # 去数据库查询所有的书籍
        data = models.Book.objects.all()
        return render(request, "book_list.html", {"book_list": data})
    
    
    class AddBook(views.View):
    
        @method_decorator(login_check)
        def get(self, request):
            data = models.Publisher.objects.all()
            return render(request, "add_book.html", {"publisher_list": data})
    
        def post(self, request):
            book_name = request.POST.get("title")
            publisher_id = request.POST.get("publisher")
            # publisher_obj = models.Publisher.objects.get(id=publisher_id)
            # 创建书籍
            models.Book.objects.create(
                title=book_name,
                publisher_id=publisher_id
                # publisher=publisher_obj #麻烦,不推荐
            )
            return redirect("/book_list/")
    
    
    class DeleteBook(views.View):
        def get(self, request, pk):
            models.Book.objects.filter(id=pk).delete()
            return redirect("/book_list/")
    
    
    class EditBook(views.View):
        def get(self, request, pk):
            book_obj = models.Book.objects.get(id=pk)
            publisher_list = models.Publisher.objects.all()
            return render(request, "edit_book.html", {"book": book_obj, "publisher_list": publisher_list})
    
        def post(self, request, pk):
            book_obj = models.Book.objects.get(id=pk)
            new_title = request.POST.get("title")
            new_publisher_id = request.POST.get("publisher")
            # 更新
            book_obj.title = new_title
            book_obj.publisher_id = new_publisher_id
            # 同步到数据库
            book_obj.save()
            return redirect("/book_list/")
    书籍相关的views.py
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>编辑书籍</title>
    </head>
    <body>
    
    <form action="" method="post">
    {% csrf_token %}
        <input type="text" name="title" value="{{ book.title }}">
        <select name="publisher">
            {% for publisher in publisher_list %}
    
                {% if book.publisher == publisher %}
                    <option selected value="{{ publisher.id }}">{{ publisher.name }}</option>
                {% else %}
                    <option value="{{ publisher.id }}">{{ publisher.name }}</option>
                {% endif %}
            {% endfor %}
        </select>
        <input type="submit" value="提交">
    </form>
    </body>
    </html>
    edit_book.html
    # 登录
    def login(request):
        if request.method == "POST":
            next = request.GET.get("next")
            username = request.POST.get("username")
            pwd = request.POST.get("pwd")
    
            if username == "alex" and pwd == "alexdsb":
                if next:
                    rep = redirect(next)
                else:
                    rep = redirect("/publisher_list/")
                # 在返回响应的时候 告诉浏览器保存我指定的键值对(cookie)
                # rep.set_cookie("s21", "hao", max_age=7)  # 7秒钟有效的Cookie
                rep.set_signed_cookie("s21", "hao", salt="ooxx", max_age=7)  # 设置加盐的cookie
                return rep
            else:
                return HttpResponse("滚~")
    
        return render(request, "login.html")
    
    
    
    # 装饰器版本登录认证
    def login_check(func):
        @wraps(func)
        def inner(request, *args, **kwargs):
            next = request.path_info
            # 登录验证
            # v = request.COOKIES.get("s21")  # 取正常的cookie
            v = request.get_signed_cookie("s21", default="", salt="ooxx")  # 获取加盐的cookie
            if v == "hao":
                return func(request, *args, **kwargs)
            else:
                return redirect("/login/?next={}".format(next))
    
        return inner
    登录的view


    七、cookie和session

    浏览器可以拒绝保存Cookie.在浏览器的settings中搜索cookie,禁用即可!
    补充3点:
    1. 如何登陆后再跳转回之前访问的页面 --> next参数实现
    2. 如何将FBV的装饰器应用到CBV上 --> from django.utils.decorators import method_decorator
    3. 装饰器修复技术 --> from functools import wraps

    form表单中的action不要写死 ,应是<form action="" method="post">

    函数的装饰器能否 直接给类使用??--不可以
    需要用method_decorator 装饰一下

    # 登录
    def login(request):
        if request.method == "POST":
            next = request.GET.get("next")
            username = request.POST.get("username")
            pwd = request.POST.get("pwd")
    
            if username == "alex" and pwd == "alexdsb":
                if next:
                    rep = redirect(next)
                else:
                    rep = redirect("/publisher_list/")
                # 在返回响应的时候 告诉浏览器保存我指定的键值对(cookie)
                # rep.set_cookie("s21", "hao", max_age=7)  # 7秒钟有效的Cookie
                rep.set_signed_cookie("s21", "hao", salt="ooxx", max_age=7)  # 设置加盐的cookie
                return rep
            else:
                return HttpResponse("滚~")
    
        return render(request, "login.html")
    
    
    #使用
    def publisher_list(request):
        # 从请求中找有没有我之前登录时候保存的特殊的键值对
        print(request.COOKIES)
        v = request.COOKIES.get("s21")
        # 如果你请求携带的值 和我之前让你保存的是同一个,就表示你是已经登陆过的用户,默认放行
        if v == "hao":
            print(request.path_info)
            data = models.Publisher.objects.all()
            return render(request, "publisher_list.html", {"publisher_list": data})
        else:
            return redirect("/login/")
    cookie的简单应用
    
    
    # 装饰器版本登录认证
    def login_check(func):
        @wraps(func) #装饰器修复技术
        def inner(request, *args, **kwargs):
            next = request.path_info  # 获取当前路径
            # 登录验证
            # v = request.COOKIES.get("s21")  # 取正常的cookie
            v = request.get_signed_cookie("s21", default="", salt="ooxx")  # 获取加盐的cookie
            if v == "hao":
                return func(request, *args, **kwargs)  # 你要执行的视图函数
            else:
                return redirect("/login/?next={}".format(next))
    
        return inner
    
    
    
    
    
    
    # 登录
    def login(request):
        if request.method == "POST":
            next = request.GET.get("next")
            username = request.POST.get("username")
            pwd = request.POST.get("pwd")
    
            if username == "alex" and pwd == "alexdsb":
                if next:
                    rep = redirect(next)
                else:
                    rep = redirect("/publisher_list/")
                # 在返回响应的时候 告诉浏览器保存我指定的键值对(cookie)
                # rep.set_cookie("s21", "hao", max_age=7)  # 7秒钟有效的Cookie
                rep.set_signed_cookie("s21", "hao", salt="ooxx", max_age=7)  # 设置加盐的cookie
                return rep
            else:
                return HttpResponse("滚~")
    
        return render(request, "login.html")
    装饰器版登录
    @login_check
    def book_list(request):
        # 去数据库查询所有的书籍
        data = models.Book.objects.all()
        return render(request, "book_list.html", {"book_list": data})
    
    
    from django.utils.decorators import method_decorator
    
    class AddBook(views.View):
    
        @method_decorator(login_check)
        def get(self, request):
            data = models.Publisher.objects.all()
            return render(request, "add_book.html", {"publisher_list": data})
    
        def post(self, request):
            book_name = request.POST.get("title")
            publisher_id = request.POST.get("publisher")
            # publisher_obj = models.Publisher.objects.get(id=publisher_id)
            # 创建书籍
            models.Book.objects.create(
                title=book_name,
                publisher_id=publisher_id
                # publisher=publisher_obj #麻烦,不推荐
            )
            return redirect("/book_list/")
    装饰器版登录应用

    装饰器修复技术---@warppers
    --动态添加功能+显示被装饰函数信息
    from functools import wraps
    
    
    def wrapper(func):
        @wraps(func)  # 借助内置的工具修复被装饰的函数
        def inner(*args, **kwargs):
            print("呵呵")
            func(*args, **kwargs)
        return inner
    
    
    @wrapper
    def foo(arg):
        """
        这是一个测试装饰器的函数
        :param arg: int 必须是int类型
        :return: None
        """
        print("嘿嘿嘿" * arg)
    
    
    foo(10)
    print(foo.__doc__)
    代码


  • 相关阅读:
    VS Code中编写C
    Latex
    JAVA学习-----容器和数据结构
    Markdown2最最基本操作说明(未完待续)
    [lua] table.sort(_table, comp)使用要点
    [coco2d]pageView:addPage时,page无法对齐
    [cocos2d]修改富文本文本和高度
    [cocos2d]格式化获取当前layer的控件名
    [c++]牛客刷题记录2.18
    [c++]STL学习
  • 原文地址:https://www.cnblogs.com/lijie123/p/10251282.html
Copyright © 2020-2023  润新知