• 第十一篇 Django 【进阶篇】


    django相关知识点

    补充

    1 .离线脚本

    -插入单条数据

    创建文件夹->项目目录/scripts
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import os
    import sys
    import django
    
    base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.append(base_dir)
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "s25.settings")
    django.setup()  # os.environ['DJANGO_SETTINGS_MODULE']
    
    
    from web import models
    # 往数据库添加数据:链接数据库、操作、关闭链接
    models.UserInfo.objects.create(username='陈硕', email='chengshuo@live.com', mobile_phone='13838383838', password='123123')
    插入单条数据

    封装一下

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import os
    import sys
    import django
    
    base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.append(base_dir)
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "s25.settings")
    django.setup()  # os.environ['DJANGO_SETTINGS_MODULE']
    base.py
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import base
    from web import models
    
    
    def run():
        models.PricePolicy.objects.create(
            title='VIP',
            price=100,
            project_num=50,
            project_member=10,
            project_space=10,
            per_file_size=500,
            category=2
        )
    
        models.PricePolicy.objects.create(
            title='SVIP',
            price=200,
            project_num=150,
            project_member=110,
            project_space=110,
            per_file_size=1024,
            category=2
        )
    
        models.PricePolicy.objects.create(
            title='SSVIP',
            price=500,
            project_num=550,
            project_member=510,
            project_space=510,
            per_file_size=2048,
            category=2
        )
    
    
    if __name__ == '__main__':
        run()
    create_price_police.py
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import base
    from web import models
    
    
    def run():
        exists = models.PricePolicy.objects.filter(category=1, title="个人免费版").exists()
        if not exists:
            models.PricePolicy.objects.create(
                category=1,
                title="个人免费版",
                price=0,
                project_num=3,
                project_member=2,
                project_space=20,
                per_file_size=5
            )
    
    
    if __name__ == '__main__':
        run()
    init_price_police.py

    -插入多条数据

    #!UsersLocalProgramsPython37
    # -*- coding: utf-8 -*-
    
    import base
    import os,json
    from yuqing import models
    
    
    def save_data_jsonl(data_dict_list,path="./new_id_source.jsonl"):
        """将数据保存为jsonl格式"""
        with open(path,mode='a',encoding="utf-8") as fp:
            for data_dict in data_dict_list:
                fp.write(json.dumps(data_dict,ensure_ascii=False)+"
    ")
    def read_jsonl(path="./baidu.jsonl"):
        """读取jsonl文件,返回字典对象列表"""
        data_dict_list=[]
        with open(path,mode="r",encoding="utf-8") as fp:
            lines =fp.readlines()
            for line in lines:
                data_dict =json.loads(line)
                data_dict_list.append(data_dict)
        return data_dict_list
    
    def run():
    
        """批量插入新闻详情数据"""
        file_list = os.listdir('F:/yuqing/hspublic_sentiment/crawl_spider/data') # 文件列表
        for item in file_list:
            print(item)
            news_obj_list =[]
            obj_list =read_jsonl(path=f"F:/yuqing/hspublic_sentiment/crawl_spider/data/{item}")
            for obj in obj_list:
                # web_source_id = obj.pop('web_source')
                # hospital_id =obj.pop("hospital")
                # obj["web_source_id"] =int(web_source_id) # 将字典中的web_source改为web_source_id
                # obj["hospital_id"] =int(hospital_id)
                news_obj_list.append(models.NewsDetail(**obj))
            models.NewsDetail.objects.bulk_create(news_obj_list)
    
        print("搞定")
    # def test():
    #     news_obj =[]
    #     obj={"title": "这种肝病发病率已超甲肝 专家:接种疫苗是最好的预防方式", "url": "https://baijiahao.baidu.com/s?id=1694666959262889051&wfr=spider&for=pc", "release_time": "2021-03-19", "web_source": 1, "hospital": 7, "source": "潇湘名医", "article_abstract": "“爱肝护肝、防治结合、遏制肝炎”义诊活动现场 见圳客户端·深圳新闻网2021年3月19日讯(记者 刘梦婷 实习记者 王莉琳)为保障人民身体健康,推动肝病防治工作,2021年3月18日,深圳市中国科学院大学深圳医院(光明)楼村工业社区健康..."}
    #     obj2 ={"title": "中科院深理工用地方案获批 位于光明新湖街道,用地面积逾……", "url": "https://baijiahao.baidu.com/s?id=1696520284290792070&wfr=spider&for=pc", "release_time": "2021-04-09", "web_source": 1, "hospital": 7, "source": "二三里资讯深圳", "article_abstract": "中国科学院深圳理工大学位于新湖街道,为公共管理与公共服务用地,用地面积474466.65平方米,转用面积24.6220公顷。中山大学附属第七医院(深圳)二期位于新湖街道,为公共管理与公共服务用地,转用面积1.3215公顷。来源:深圳新闻网声明:..."}
    #
    #     web_source_id = obj.pop('web_source')
    #     hospital_id = obj.pop("hospital")
    #     obj["web_source_id"] = int(web_source_id)
    #     obj["hospital_id"] = int(hospital_id)
    #     print(obj)
    #     news_obj.append(models.NewsDetail(**obj))
    #
    #     web_source_id = obj2.pop('web_source')
    #     hospital_id = obj2.pop("hospital")
    #     obj2["web_source_id"] = int(web_source_id)
    #     obj2["hospital_id"] = int(hospital_id)
    #     print(obj2)
    #     news_obj.append(models.NewsDetail(**obj2))
    #     print(news_obj)
    #
    #     models.NewsDetail.objects.bulk_create(news_obj)
    
    if __name__ == '__main__':
        # run()
        # test()
        pass
    buik_create批量插入


    1 路由--视图

      1 4.1 简单的路由配置(下拉-->4.6为path匹配)
      2 from django.urls import path,re_path
      3 from app01 import views
      4 
      5 urlpatterns = [
      6 re_path(r'^articles/2003/$', views.special_case_2003),
      7 re_path(r'^articles/([0-9]{4})/$', views.year_archive),
      8 re_path(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
      9 re_path(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
     10 ]
     11 注意:一对圆括号 -->>从URL 中捕获一个值
     12 
     13 4.2 有名分组 ?P<name>
     14 
     15 from django.urls import path,re_path
     16 from app01 import views
     17 
     18 urlpatterns = [
     19 re_path(r'^articles/2003/$', views.special_case_2003),
     20 re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
     21 re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
     22 re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
     23 ]
     24 解释:
     25 /articles/2005/03/ 请求将调用views.month_archive(request, year='2005', month='03')函数,而不是views.month_archive(request, '2005', '03')。
     26 /articles/2003/03/03/ 请求将调用函数views.article_detail(request, year='2003', month='03', day='03')。
     27 
     28 4.3 分发
     29 
     30 from django.urls import path,re_path,include
     31 from app01 import views
     32 
     33 urlpatterns = [
     34 re_path(r'^admin/', admin.site.urls),
     35 re_path(r'^blog/', include('blog.urls')),
     36 ]
     37 
     38 4.4 反向解析
     39 在使用Django 项目时,一个常见的需求是获得URL 的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。人们强烈希望不要硬编码这些URL(费力、不可扩展且容易产生错误)或者设计一种与URLconf 毫不相关的专门的URL 生成机制,因为这样容易导致一定程度上产生过期的URL。 在需要URL 的地方,对于不同层级,Django 提供不同的工具用于URL 反查:
     40 
     41 在模板中:使用url 模板标签。
     42 在Python 代码中:使用from django.urls import reverse()函数 urls.py:
     43 from django.conf.urls import url
     44 from . import views
     45 
     46 urlpatterns = [
     47 #...
     48 re_path(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
     49 #...
     50 ]
     51 
     52 在模板中:
     53 
     54 <a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
     55 
     56 <ul>
     57 {% for yearvar in year_list %}
     58 <li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
     59 {% endfor %}
     60 </ul>
     61 在python中:
     62 
     63 from django.urls import reverse
     64 from django.http import HttpResponseRedirect
     65 
     66 def redirect_to_year(request):
     67 # ...
     68 year = 2006
     69 # ...
     70 return HttpResponseRedirect(reverse('news-year-archive', args=(year,))) # 同redirect("/path/")
     71 
     72 4.5 名称空间
     73 
     74 project的urls.py:
     75 
     76 urlpatterns = [
     77 re_path(r'^admin/', admin.site.urls),
     78 re_path(r'^app01/', include(("app01.urls","app01"))),  #传递一个元组
     79 re_path(r'^app02/', include("app02.urls","app02")),
     80 ]
     81 app01.urls:
     82 
     83 urlpatterns = [
     84 re_path(r'^index/', index,name="index"),
     85 ]
     86 app02.urls:
     87 
     88 urlpatterns = [
     89 re_path(r'^index/', index,name="index"),
     90 ]
     91 app01.views
     92 
     93 from django.core.urlresolvers import reverse
     94 def index(request):
     95 return HttpResponse(reverse("app01:index"))
     96 app02.views
     97 
     98 from django.core.urlresolvers import reverse
     99 def index(request):
    100 return HttpResponse(reverse("app02:index"))
    101 
    102 4.6 django2.0版的path
    103 
    104 基本示例:
    105 from django.urls import path  
    106 from . import views  
    107 urlpatterns = [  
    108     path('articles/2003/', views.special_case_2003),  
    109     path('articles/<int:year>/', views.year_archive),  
    110     path('articles/<int:year>/<int:month>/', views.month_archive),  
    111     path('articles/<int:year>/<int:month>/<slug>/', views.article_detail),  
    112 ]
    113 基本规则:
    114 
    115 使用尖括号(<>)从url中捕获值。
    116 捕获值中可以包含一个转化器类型(converter type),比如使用 捕获一个整数变量。若果没有转化器,将匹配任何字符串,当然也包括了 / 字符。
    117 无需添加前导斜杠。
    118 以下是根据https://docs.djangoproject.com/en/2.0/topics/http/urls/#example而整理的示例分析表:
    119 
    120 
    121 
    122 4.7path转化器
    123 文档原文是Path converters,暂且翻译为转化器。
    124 Django默认支持以下5个转化器:
    125 
    126 str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
    127 int,匹配正整数,包含0。
    128 slug,匹配字母、数字以及横杠、下划线组成的字符串。
    129 uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
    130 path,匹配任何非空字符串,包含了路径分隔符
    131 注册自定义转化器
    132 对于一些复杂或者复用的需要,可以定义自己的转化器。转化器是一个类或接口,它的要求有三点:
    133 
    134 regex 类属性,字符串类型
    135 to_python(self, value) 方法,value是由类属性 regex 所匹配到的字符串,返回具体的Python变量值,以供Django传递到对应的视图函数中。
    136 to_url(self, value) 方法,和 to_python 相反,value是一个具体的Python变量值,返回其字符串,通常用于url反向引用。
    137 例子:
    138 
    139 class FourDigitYearConverter:  
    140     regex = '[0-9]{4}'  
    141     def to_python(self, value):  
    142         return int(value)  
    143     def to_url(self, value):  
    144         return '%04d' % value
    145 使用register_converter 将其注册到URL配置中:
    146 
    147 from django.urls import register_converter, path  
    148 from . import converters, views  
    149 register_converter(converters.FourDigitYearConverter, 'yyyy')  
    150 urlpatterns = [  
    151     path('articles/2003/', views.special_case_2003),  
    152     path('articles/<yyyy:year>/', views.year_archive),  
    153     ...  
    154 ]
    路由
    视图层
    #1视图响应常用示例:
    小知识:make_safe 的使用,不转义
    
    from django.shortcuts import render, HttpResponse, HttpResponseRedirect, redirect
    from django.utils.safestring import mark_safe
    import datetime
    
    def current_datetime(request):
        now = datetime.datetime.now()
        html = mark_safe("<html><body>It is now %s.</body></html>" % now)
        return HttpResponse(html)
    
    #响应对象主要有三种形式:
    -- HttpResponse()
    -- render()
    -- redirect()
    
    #2request属性与方法
    
    1.HttpRequest.GET
    
    2.HttpRequest.POST
           # if contentType==urlencoded ,request.POST才有数据
    
    3.HttpRequest.body
    
    4.HttpRequest.path
      一个字符串,表示请求的路径组件(不含域名)。
      例如:"/music/bands/the_beatles/"
    
    5.HttpRequest.method
      一个字符串,表示请求使用的HTTP 方法。必须使用大写。
      例如:"GET""POST"
    
    6.HttpRequest.encoding
    
    7.HttpRequest.META
       一个标准的Python 字典,包含所有的HTTP 首部。具体的头部信息取决于客户端和服务器,下面是一些示例:
        CONTENT_LENGTH —— 请求的正文的长度(是一个字符串)。
        CONTENT_TYPE —— 请求的正文的MIME 类型。
        HTTP_ACCEPT —— 响应可接收的Content-Type。
        HTTP_ACCEPT_ENCODING —— 响应可接收的编码。
        HTTP_ACCEPT_LANGUAGE —— 响应可接收的语言。
        HTTP_HOST —— 客服端发送的HTTP Host 头部。
        HTTP_REFERER —— Referring 页面。
        HTTP_USER_AGENT —— 客户端的user-agent 字符串。
        QUERY_STRING —— 单个字符串形式的查询字符串(未解析过的形式)。
        REMOTE_ADDR —— 客户端的IP 地址。
        REMOTE_HOST —— 客户端的主机名。
        REMOTE_USER —— 服务器认证后的用户。
        REQUEST_METHOD —— 一个字符串,例如"GET""POST"。
        SERVER_NAME —— 服务器的主机名。
        SERVER_PORT —— 服务器的端口(是一个字符串)。
       从上面可以看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 之外,请求中的任何 HTTP 首部转换为 META 的键时,
        都会将所有字母大写并将连接符替换为下划线最后加上 HTTP_  前缀。
        所以,一个叫做 X-Bender 的头部将转换成 META 中的 HTTP_X_BENDER 键。
    
    8.HttpRequest.FILES
      一个类似于字典的对象,包含所有的上传文件信息。
       FILES 中的每个键为<input type="file" name="" /> 中的name,值则为对应的数据。
      注意,FILES 只有在请求的方法为POST 且提交的<form> 带有enctype="multipart/form-data" 的情况下才会
       包含数据。否则,FILES 将为一个空的类似于字典的对象。
    
    9.HttpRequest.COOKIES
     
    10.HttpRequest.session
    
    11.HttpRequest.user(用户认证组件下使用)
      一个 AUTH_USER_MODEL 类型的对象,表示当前登录的用户。
      如果用户当前没有登录,user 将设置为 django.contrib.auth.models.AnonymousUser 的一个实例。你可以通过 is_authenticated() 区分它们。
    
        例如:
        if request.user.is_authenticated():
            # Do something for logged-in users.
        else:
            # Do something for anonymous users.
           user 只有当Django 启用 AuthenticationMiddleware 中间件时才可用。
         -------------------------------------------------------------------------------------
        匿名用户
        class models.AnonymousUser
        django.contrib.auth.models.AnonymousUser 类实现了django.contrib.auth.models.User 接口,但具有下面几个不同点:
        id 永远为None。
        username 永远为空字符串。
        get_username() 永远返回空字符串。
        is_staff 和 is_superuser 永远为False。
        is_active 永远为 False。
        groups 和 user_permissions 永远为空。
        is_anonymous() 返回True 而不是False。
        is_authenticated() 返回False 而不是True。
        set_password()、check_password()、save() 和delete() 引发 NotImplementedError。
        New in Django 1.8:
        新增 AnonymousUser.get_username() 以更好地模拟 django.contrib.auth.models.User。
    
    
    # request常用方法
    
    1.HttpRequest.get_full_path()
      返回 path,如果可以将加上查询字符串。
      例如:"/music/bands/the_beatles/?print=true"
    2.HttpRequest.is_ajax()
      如果请求是通过XMLHttpRequest 发起的,则返回True,方法是检查 HTTP_X_REQUESTED_WITH 相应的首部是否是字符串'XMLHttpRequest'。
      大部分现代的 JavaScript 库都会发送这个头部。如果你编写自己的 XMLHttpRequest 调用(在浏览器端),你必须手工设置这个值来让 is_ajax() 可以工作。
      如果一个响应需要根据请求是否是通过AJAX 发起的,并且你正在使用某种形式的缓存例如Django 的 cache middleware,
       你应该使用 vary_on_headers('HTTP_X_REQUESTED_WITH') 装饰你的视图以让响应能够正确地缓存。
    视图参数
    from django.shortcuts import render,HttpResponse
    
    # Create your views here.
    
    from django.urls import reverse # 反向解析
    def special_case_2003(request):
        url= reverse('s_c_2005')
        url2 = reverse('y',args=(1993,))
        print(url) # 反向解析
        print(url2)
    
        return HttpResponse("special_case_2003")
    
    def year_archive(request,y):
        return HttpResponse(y)
    
    def month_archive(request,year,month):
        return HttpResponse(month+"-"+year)
    
    def login(request):
        print(request.method)
        if request.method=='GET':
            return render(request, 'login.html')
        else:
            print(request.POST)
            user = request.POST.get('user')
            pwd = request.POST.get('pwd')
    
            if user =='HW' and pwd =='123':
                return HttpResponse('登陆成功')
            else:
                return  HttpResponse('账号或者密码错误哦!!')
    
    def index(request):
        return HttpResponse(reverse('app01:index'))
    
    def path_year(request,year):
        print(type(year))
        return HttpResponse('path_year...')
    def path_month(request,month):
        return  HttpResponse('path_month...')
    视图示例

    2 模板

    django 模板
    
    #6.1 模板语法之变量
    在 Django 模板中遍历复杂数据结构的关键是句点字符, 语法:
    {{var_name}}
    
    views.py:
    
    def index(request):
        import datetime
        s="hello"
        l=[111,222,333]    # 列表
        dic={"name":"yuan","age":18}  # 字典
        date = datetime.date(1993, 5, 2)   # 日期对象
    
        class Person(object):
            def __init__(self,name):
                self.name=name
    
        person_yuan=Person("yuan")  # 自定义类对象
        person_egon=Person("egon")
        person_alex=Person("alex")
        person_list=[person_yuan,person_egon,person_alex]
    
        #return render(request,'index.html',locals())
        return render(request,"index.html",{"l":l,"dic":dic,"date":date,"person_list":person_list})
    template:
    
    <h4>{{s}}</h4>
    <h4>列表:{{ l.0 }}</h4>
    <h4>列表:{{ l.2 }}</h4>
    <h4>字典:{{ dic.name }}</h4>
    <h4>日期:{{ date.year }}</h4>
    <h4>类对象列表:{{ person_list.0.name }}</h4>
    <h4>字典:{{ dic.name.upper }}</h4>
    
    #6.2 模板之过滤器
    语法:
    {{obj|filter__name:param}}
    
    1default
    如果一个变量是false或者为空,使用给定的默认值。否则,使用变量的值。例如:
    {{ value|default:"nothing" }}
    
    2length
    返回值的长度。它对字符串和列表都起作用。例如:
    {{ value|length }}
    如果 value 是 ['a', 'b', 'c', 'd'],那么输出是 4。
    
    3date
    如果 value=datetime.datetime.now()
    {{ value|date:"Y-m-d" }}
    
    4slice
    如果 value="hello world"
    {{ value|slice:"2:-1" }}
    
    5truncatechars
    如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。
    参数:要截断的字符数
    例如:
    {{ value|truncatechars:9 }}
    
    6safe
    Django的模板中会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全。但是有的时候我们可能不希望这些HTML元素被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。为了在Django中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义。比如:
    value="<a href="">点击</a>"
    {{ value|safe}}
    
    ##6.3 模板之标签 
    标签看起来像是这样的: {% tag %}
    
    1for标签
    a.遍历每一个元素:
    b.反向完成循环。{% for obj in list reversed %}
    c.遍历一个字典:
    {% for key,val in dic.items %}
        <p>{{ key }}:{{ val }}</p>
    {% endfor %}
    注:循环序号可以通过{{forloop}}显示 
    forloop.counter            The current iteration of the loop (1-indexed)
    forloop.counter0           The current iteration of the loop (0-indexed)
    forloop.revcounter         The number of iterations from the end of the loop (1-indexed)
    forloop.revcounter0        The number of iterations from the end of the loop (0-indexed)
    forloop.first              True if this is the first time through the loop
    forloop.last               True if this is the last time through the loop
    d.for ... empty
    for 标签带有一个可选的{% empty %} 从句,以便在给出的组是空的或者没有被找到时,可以有所操作。
    
    {% for person in person_list %}
        <p>{{ person.name }}</p>
    {% empty %}
        <p>sorry,no person here</p>
    {% endfor %}
    
    2if 标签
    {% if %}
    
    {% if num > 100 or num < 0 %}
        <p>无效</p>
    {% elif num > 80 and num < 100 %}
        <p>优秀</p>
    {% else %}
        <p>凑活吧</p>
    {% endif %}
    
    3with
    使用一个简单地名字缓存一个复杂的变量,当你需要使用一个“昂贵的”方法(比如访问数据库)很多次的时候是非常有用的
    例如:
    {% with total=business.employees.count %}
        {{ total }} employee{{ total|pluralize }}
    {% endwith %}
    
    4csrf_token
    这个标签用于跨站请求伪造保护
    {% csrf_token}
    
    #6.4 自定义标签和过滤器
    1、在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag.
    2、在app中创建templatetags模块(模块名只能是templatetags)
    3、创建任意 .py 文件,如:my_tags.py
    
      from django import template
      from django.utils.safestring import mark_safe
      register = template.Library()   #register的名字是固定的,不可改变  
      @register.filter
      def filter_multi(v1,v2):
          return  v1 * v2
    
      @register.simple_tag
      def simple_tag_multi(v1,v2):
          return  v1 * v2
    
      @register.simple_tag
      def my_input(id,arg):
          result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
          return mark_safe(result)
    4、在使用自定义simple_tag和filter的html文件中导入之前创建的 my_tags.py
    
          {% load my_tags %}
    5、使用simple_tag和filter(如何调用)
    
      -------------------------------.html
      {% load xxx %}        
      # num=12
      {{ num|filter_multi:2 }} #24
      {{ num|filter_multi:"[22,333,4444]" }}
      {% simple_tag_multi 2 5 %}  参数不限,但不能放在if for语句中
      {% simple_tag_multi num 5 %}
    注意:filter可以用在if等语句后,simple_tag不可以
    
    {% if num|filter_multi:30 > 100 %}
        {{ num|filter_multi:30 }}
    {% endif %}
    
    6.5 模板继承 (extend)
    示例:
    base.html:
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <link rel="stylesheet" href="style.css" />
        <title>{% block title %}My amazing site{% endblock %}</title>
    </head>
    
    <body>
        <div id="sidebar">
            {% block sidebar %}
            <ul>
                <li><a href="/">Home</a></li>
                <li><a href="/blog/">Blog</a></li>
            </ul>
            {% endblock %}
        </div>
    
        <div id="content">
            {% block content %}{% endblock %}
        </div>
    </body>
    </html>
    
    子模版:
    {% extends "base.html" %}
    
    {% block title %}My amazing blog{% endblock %}
    
    {% block content %}
    {% for entry in blog_entries %}
        <h2>{{ entry.title }}</h2>
        <p>{{ entry.body }}</p>
    {% endfor %}
    {% endblock content %}
    
    注意:子模版并没有定义 sidebar block,所以系统使用了父模版中的值。父模版的 {% block %} 标签中的内容总是被用作备选内容(fallback)。
    模板
    ----- inclution_tag的使用 (文章详情页与个人站点共用一套动态渲染的模板)
    应用:个人站点页面设计(ORM跨表与分组查询)
        1 inclution_tag的使用 (文章详情页与个人站点共用一套动态渲染的模板)
        2 orm查询中使用sql语句(extra方法的使用)
    
    
    使用:
    1 在当前应用app文件目录下--->创建一个templatetags文件夹----->创建一个py文件,比如my_tags.py
    2 my_tags.py 中自定义标签
    
    from django import template
    from django.db.models import Count
    from blog import models
    register=template.Library()
    
    @register.inclusion_tag("classification.html")
    def get_classification_style(username):
    
        user = models.UserInfo.objects.filter(username=username).first()
        blog = user.blog
    
        cate_list=models.Category.objects.filter(blog=blog).values("pk").annotate(c=Count("article__title")).values_list("title","c")
    
        tag_list=models.Tag.objects.filter(blog=blog).values("pk").annotate(c=Count("article")).values_list("title","c")
    
        date_list=models.Article.objects.filter(user=user).extra(select={"y_m_date":"date_format(create_time,'%%Y/%%m')"}).values("y_m_date").annotate(c=Count("nid")).values_list("y_m_date","c")
    
    
        return {"blog":blog,"cate_list":cate_list,"date_list":date_list,"tag_list":tag_list}
    
    3 在模板下创建classification.html文件
    # classification.html文件
     <div>
        <div class="panel panel-warning">
                    <div class="panel-heading">我的标签</div>
                    <div class="panel-body">
                        {% for tag in tag_list %}
                            <p><a href="/{{ username }}/tag/{{ tag.0 }}">{{ tag.0 }}({{ tag.1 }})</a></p>
                        {% endfor %}
    
                    </div>
                </div>
    
        <div class="panel panel-danger">
            <div class="panel-heading">随笔分类</div>
            <div class="panel-body">
                {% for cate in cate_list %}
                    <p><a href="/{{ username }}/category/{{ cate.0 }}">{{ cate.0 }}({{ cate.1 }})</a></p>
                {% endfor %}
            </div>
        </div>
    
        <div class="panel panel-success">
            <div class="panel-heading">随笔归档</div>
            <div class="panel-body">
                {% for date in date_list %}
                    <p><a href="/{{ username }}/archive/{{ date.0 }}">{{ date.0 }}({{ date.1 }})</a></p>
                {% endfor %}
            </div>
        </div>
     </div>
    
    4 使用标签
         {% load my_tags %}
         {% get_classification_style username %}
    
    解释:这个自定义的标签get_classification_style一旦在模板中被调用,
    首先会执行get_classification_style函数内的逻辑然后将返回的数据传送给模板classification.html去渲染,
    渲染完的结果就是这次get_classification_style标签调用的返回值。
    incluttion_tag

    3  orm

    
    
    from django.db import models
    from django.contrib.auth.models import AbstractUser
    # 使用django自带的user表,增加字段
    class UserInfo(AbstractUser):
    """
    用户信息
    注意:用到django认证组件,需要继承AbstractUser
    头像上传(media使用)
    """
    nid = models.AutoField(primary_key=True)
    telephone = models.CharField(max_length=11, null=True, unique=True)
    avatar = models.FileField(verbose_name='头像图片文件',upload_to='avatars/', default="/avatars/default.png")
    create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)

    blog = models.OneToOneField(to='Blog', to_field='nid', null=True, on_delete=models.CASCADE)

    def __str__(self):
    return self.username

    class Employee(models.Model): id
    =models.AutoField(primary_key=True) name=models.CharField(max_length=32) gender=models.BooleanField() birthday=models.DateField() department=models.CharField(max_length=32) salary=models.DecimalField(max_digits=8,decimal_places=2) #python的类对象 #添加一条表纪录: emp=Employee(name="alex",gender=True,birthday="1985-12-12",epartment="保洁部") emp.save() #查询一条表纪录: Employee.objects.filter(age=24) #更新一条表纪录: Employee.objects.filter(id=1).update(birthday="1989-10-24") #删除一条表纪录: Employee.objects.filter(name="alex").delete()
    字段
    <1> CharField
           字符串字段, 用于较短的字符串.
           CharField 要求必须有一个参数 maxlength, 用于从数据库层和Django校验层限制该字段所允许的最大字符数.
    
    <2> IntegerField
          #用于保存一个整数.
    
    <3> FloatField
           一个浮点数. 必须 提供两个参数:
    
           参数    描述
           max_digits    总位数(不包括小数点和符号)
           decimal_places    小数位数
                   举例来说, 要保存最大值为 999 (小数点后保存2位),你要这样定义字段:
    
                   models.FloatField(..., max_digits=5, decimal_places=2)
                   要保存最大值一百万(小数点后保存10位)的话,你要这样定义:
    
                   models.FloatField(..., max_digits=19, decimal_places=10)
                   admin 用一个文本框(<input type="text">)表示该字段保存的数据.
    
    <4> AutoField
           一个 IntegerField, 添加记录时它会自动增长. 你通常不需要直接使用这个字段;
           自定义一个主键:my_id=models.AutoField(primary_key=True)
           如果你不指定主键的话,系统会自动添加一个主键字段到你的 model.
    
    <5> BooleanField
           A true/false field. admin 用 checkbox 来表示此类字段.
    
    <6> TextField
           一个容量很大的文本字段.
           admin 用一个 <textarea> (文本区域)表示该字段数据.(一个多行编辑框).
    
    <7> EmailField
           一个带有检查Email合法性的 CharField,不接受 maxlength 参数.
    
    <8> DateField
           一个日期字段. 共有下列额外的可选参数:
           Argument    描述
           auto_now    当对象被保存时,自动将该字段的值设置为当前时间.通常用于表示 "last-modified" 时间戳.
           auto_now_add    当对象首次被创建时,自动将该字段的值设置为当前时间.通常用于表示对象创建时间.
           (仅仅在admin中有意义...)
    
    <9> DateTimeField
            一个日期时间字段. 类似 DateField 支持同样的附加选项.
    
    <10> ImageField
           类似 FileField, 不过要校验上传对象是否是一个合法图片.#它有两个可选参数:height_field和width_field,
           如果提供这两个参数,则图片将按提供的高度和宽度规格保存.    
    <11> FileField
        一个文件上传字段.
        要求一个必须有的参数: upload_to, 一个用于保存上载文件的本地文件系统路径. 这个路径必须包含 strftime #formatting,
        该格式将被上载文件的 date/time
        替换(so that uploaded files don't fill up the given directory).
        admin 用一个<input type="file">部件表示该字段保存的数据(一个文件上传部件) .
    
        注意:在一个 model 中使用 FileField 或 ImageField 需要以下步骤:
               (1)在你的 settings 文件中, 定义一个完整路径给 MEDIA_ROOT 以便让 Django在此处保存上传文件.
               (出于性能考虑,这些文件并不保存到数据库.) 定义MEDIA_URL 作为该目录的公共 URL. 要确保该目录对
                WEB服务器用户帐号是可写的.
               (2) 在你的 model 中添加 FileField 或 ImageField, 并确保定义了 upload_to 选项,以告诉 Django
                使用 MEDIA_ROOT 的哪个子目录保存上传文件.你的数据库中要保存的只是文件的路径(相对于 MEDIA_ROOT).
                出于习惯你一定很想使用 Django 提供的 get_<#fieldname>_url 函数.举例来说,如果你的 ImageField
                叫作 mug_shot, 你就可以在模板中以 {{ object.#get_mug_shot_url }} 这样的方式得到图像的绝对路径.
    
    <12> URLField
         用于保存 URL. 若 verify_exists 参数为 True (默认), 给定的 URL 会预先检查是否存在( 即URL是否被有效装入且
         没有返回404响应).
         admin 用一个 <input type="text"> 文本框表示该字段保存的数据(一个单行编辑框)
    
    <13> NullBooleanField
          类似 BooleanField, 不过允许 NULL 作为其中一个选项. 推荐使用这个字段而不要用 BooleanField 加 null=True 选项
          admin 用一个选择框 <select> (三个可选择的值: "Unknown", "Yes" 和 "No" ) 来表示这种字段数据.
    
    <14> SlugField
          "Slug" 是一个报纸术语. slug 是某个东西的小小标记(短签), 只包含字母,数字,下划线和连字符.#它们通常用于URLs
          若你使用 Django 开发版本,你可以指定 maxlength. 若 maxlength 未指定, Django 会使用默认长度: 50.  #在
          以前的 Django 版本,没有任何办法改变50 这个长度.
          这暗示了 db_index=True.
          它接受一个额外的参数: prepopulate_from, which is a list of fields from which to auto-#populate
          the slug, via JavaScript,in the object's admin form: models.SlugField
          (prepopulate_from=("pre_name", "name"))prepopulate_from 不接受 DateTimeFields.
    
    <13> XMLField
           一个校验值是否为合法XML的 TextField,必须提供参数: schema_path, 它是一个用来校验文本的 RelaxNG schema #的文件系统路径.
    
    <14> FilePathField
           可选项目为某个特定目录下的文件名. 支持三个特殊的参数, 其中第一个是必须提供的.
           参数    描述
           path    必需参数. 一个目录的绝对文件系统路径. FilePathField 据此得到可选项目.
           Example: "/home/images".
           match    可选参数. 一个正则表达式, 作为一个字符串, FilePathField 将使用它过滤文件名.
           注意这个正则表达式只会应用到 base filename 而不是
           路径全名. Example: "foo.*.txt^", 将匹配文件 foo23.txt 却不匹配 bar.txt 或 foo23.gif.
           recursive可选参数.要么 True 要么 False. 默认值是 False. 是否包括 path 下面的全部子目录.
           这三个参数可以同时使用.
           match 仅应用于 base filename, 而不是路径全名. 那么,这个例子:
           FilePathField(path="/home/images", match="foo.*", recursive=True)
           ...会匹配 /home/images/foo.gif 而不匹配 /home/images/foo/bar.gif
    
    <15> IPAddressField
           一个字符串形式的 IP 地址, (i.e. "24.124.1.30").
    <16> CommaSeparatedIntegerField
           用于存放逗号分隔的整数值. 类似 CharField, 必须要有maxlength参数.
    
    更多参数:
    (1)null
    
    如果为True,Django 将用NULL 来在数据库中存储空值。 默认值是 False.
    
    (1)blank
    
    如果为True,该字段允许不填。默认为False。
    要注意,这与 null 不同。null纯粹是数据库范畴的,而 blank 是数据验证范畴的。
    如果一个字段的blank=True,表单的验证将允许该字段是空值。如果字段的blank=False,该字段就是必填的。
    
    (2)default
    
    字段的默认值。可以是一个值或者可调用对象。如果可调用 ,每有新对象被创建它都会被调用。
    
    (3)primary_key
    
    如果为True,那么这个字段就是模型的主键。如果你没有指定任何一个字段的primary_key=True,
    Django 就会自动添加一个IntegerField字段做为主键,所以除非你想覆盖默认的主键行为,
    否则没必要设置任何一个字段的primary_key=True。
    
    (4)unique
    
    如果该值设置为 True, 这个数据字段的值在整张表中必须是唯一的
    
    (5)choices
    由二元组组成的一个可迭代对象(例如,列表或元组),用来给字段提供选择项。 如果设置了choices ,默认的表单将是一个选择框而不是标准的文本框,<br>而且这个选择框的选项就是choices 中的选项。
    字段-参数
    #### 1.2 orm字段
    
    需求:前端发送json `{'key':"email"}`或`{'key':"password"}`,后端接收到数据之后,去ORM类User中校验是否允许为空。
    
    ```
    class UserInfo(models.Model):
        username = models.CharField(verbose_name='用户名', max_length=32, db_index=True)
        email = models.EmailField(verbose_name='邮箱', max_length=32,null=True)
        mobile_phone = models.CharField(verbose_name='手机号', max_length=32)
        password = models.CharField(verbose_name='密码', max_length=32)
    
    def index(request):
        data_dict = json.loads(request.body.decode('utf-8'))
        
        field_object = models.UserInfo._meta.get_field(data_dict["key"])
        print( field_object.verbose_name ) # 邮箱 ; 密码
        print( field_object.null ) # True ; False
    ```
    orm字段
    from django.db import models
    
    
    # Create your models here.
    
    # 作者详情表
    class AuthorDetail(models.Model):
        nid = models.AutoField(primary_key=True)
        birthday = models.DateField()
        telepnone = models.BigIntegerField()
        addr = models.CharField(max_length=64)
    
    
    # 作者表
    class Author(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        # 一对一
        authordetail = models.OneToOneField(to="AuthorDetail", to_field="nid", on_delete=models.CASCADE)
    
        def __str__(self):
            return self.name
    
    
    # 出版社表
    class Publish(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        city = models.CharField(max_length=32)
        email = models.EmailField()
    
        def __str__(self):
            return self.name
    
    
    # 图书表
    class Book(models.Model):
        nid = models.AutoField(primary_key=True)
        title = models.CharField(max_length=32)
        publishDate = models.DateField()
        price = models.DecimalField(max_digits=5, decimal_places=2)
    
        # 一对多关系
        publish = models.ForeignKey(to=Publish, to_field='nid', on_delete=models.CASCADE)
        '''
                publish_id INT ,
                FOREIGN KEY (publish_id) REFERENCES publish(id)
        '''
        # 多对多(生成第三张表,并不会生成字段)
        authors = models.ManyToManyField(to="Author")
        '''
            CREATE  TABLE book_authors(
               id INT PRIMARY KEY auto_increment ,
               book_id INT ,
               author_id INT ,
               FOREIGN KEY (book_id) REFERENCES book(id),
               FOREIGN KEY (author_id) REFERENCES author(id)
                )
            '''
    
        # class Book2Author(models.Model):
        #
        #     nid = models.AutoField(primary_key=True)
        #     book=models.ForeignKey(to="Book")
        #     author=models.ForeignKey(to="Author")
    
        def __str__(self):
            return self.title
    表关系

    3 单表查询--多表查询

    from django.shortcuts import render,HttpResponse
    
    # Create your views here.
    from app01.models import *
    
    
    def add(request):
    
    ######################绑定一对多的关系##############################################
        #方式1:
        #为book表绑定出版社: book  ---    publish
        # book_obj=Book.objects.create(title="红楼梦",price=100,publishDate="2012-12-12",publish_id=1)
        # print(book_obj.title)
    
        #方式2:
        # pub_obj=Publish.objects.filter(nid=1).first()
        # book_obj=Book.objects.create(title="三国演绎",price=100,publishDate="2012-12-12",publish=pub_obj)
        # print(book_obj.title)
        # print(book_obj.price)
        # print(book_obj.publishDate)
        # print(book_obj.publish)       #  与这本书籍关联的出版社对象
        # print(book_obj.publish.name)
        # print(book_obj.publish.email)
        # print(book_obj.publish_id)
    
    
        # 查询西游记的出版社对应的邮箱()
    
        # book_obj = Book.objects.filter(title="西游记").first()
        # print(book_obj.publish.email)
    
    ######################绑定多对多的关系##############################################
    
        # book_obj = Book.objects.create(title="金妹妹", price=100, publishDate="2012-12-12", publish_id=1)
        #
        # alex = Author.objects.get(name='alex')
        # egon = Author.objects.get(name='egon')
    
        # 绑定多对多关系的API
        # book_obj.authors.add(egon,alex)
        # book_obj.authors.add(1,2)
        # book_obj.authors.add(*[1, 2])
    
        # 解除多对多关系
        book = Book.objects.filter(nid=5).first()
        # book.authors.remove(2)
        # book.authors.remove(*[1,2])
        # book.authors.clear()
    
        #查询主键为4的书籍的所有作者的名字
        book=Book.objects.filter(nid=5).first()
        print(book.authors.all()) # [obj1,obj2...] queryset: 与这本书关联的所有作者对象集合
        ret=book.authors.all().values("name")
        print(ret)
        print(book.authors.all())
    
        return HttpResponse('Ok')
    
    def query(request):
        """
        跨表查询:
           1 基于对象查询 (子查询)
           2 基于双下划线查询(join查询)
           3 聚合和分组查询
           4 F 与 Q查询
        :param request:
        :return:
        """
    # -------------------------基于对象的跨表查询(子查询)-----------------------
        # 一对多查询的正向查询 : 查询金妹妹这本书的出版社的名字
        # book= Book.objects.filter(title='金妹妹').first()
        # ret =book.publish.name
        # print(ret)
        # 对应sql:
        # select publish_id from Book where title="金妹妹"
        # select name from Publish where id=1
    
        # 一对多查询的反向查询 : 查询人民出版社出版过的书籍名称
        # publish = Publish.objects.filter(name='人民出版社').first()
        # names = publish.book_set.all()
        # print(names)
    
        # 多对多查询的正向查询 : 查询金妹妹这本书的所有作者的名字
        # book_obj=Book.objects.filter(title="金妹妹").first()
        # author_list=book_obj.authors.all() # queryset对象  [author_obj1,...]
        #
        # for author in author_list:
        #     print(author.name)
    
        # 多对多查询的反向查询 : 查询alex出版过的所有书籍名称
        # alex=Author.objects.filter(name="alex").first()
        #
        # book_list=alex.book_set.all()
        # for book in book_list:
        #     print(book.title)
    
        # 一对一查询的正向查询 : 查询alex的手机号
        # alex=Author.objects.filter(name="alex").first()
        # print(alex.authordetail.telephone)
    
        # # 一对一查询的反向查询 : 查询手机号为110的作者的名字和年龄
        # ad=AuthorDetail.objects.filter(telephone="110").first()
        # print(ad.author.name)
        # print(ad.author.age)
    
    
    # -------------------------基于双下划线的跨表查询(join查询)-----------------------
    
        '''
    
        正向查询按字段,反向查询按表名小写用来告诉ORM引擎join哪张表
    
        '''
    
        # 一对多查询 : 查询金妹妹这本书的出版社的名字
    
        # 方式1:
        # ret= Book.objects.filter(title ='金妹妹').values("publish__name")
        # print(ret) # <QuerySet [{'publish__name': '南京出版社'}]>
    
        # 方式2:
        # ret=Publish.objects.filter(book__title="金妹妹").values("name")
        # print(ret)
        # 方式1:
    
        # 需求: 通过Book表join与其关联的Author表,属于正向查询:按字段authors通知ORM引擎join book_authors与author
    
        # ret=Book.objects.filter(title="金妹妹").values("authors__name")
        # print(ret) # <QuerySet [{'authors__name': 'alex'}, {'authors__name': 'egon'}]>
    
        # 方式2:
        # 需求: 通过Author表join与其关联的Book表,属于反向查询:按表名小写book通知ORM引擎join book_authors与book表
        # ret=Author.objects.filter(book__title="金妹妹").values("name")
        # print(ret) # <QuerySet [{'name': 'alex'}, {'name': 'egon'}]>
    
        # 一对一查询的查询 : 查询alex的手机号
    
        # 方式1:
        # 需求: 通过Author表join与其关联的AuthorDetail表,属于正向查询:按字段authordetail通知ORM引擎join Authordetail表
    
        # ret=Author.objects.filter(name="alex").values("authordetail__telephone")
        # print(ret) # <QuerySet [{'authordetail__telephone': 110}]>
        #
        # # 方式2:
        # # 需求: 通过AuthorDetail表join与其关联的Author表,属于反向查询:按表名小写author通知ORM引擎join Author表
        # ret=AuthorDetail.objects.filter(author__name="alex").values("telephone")
        # print(ret) # <QuerySet [{'telephone': 110}]>
    
        # 进阶练习:
    
        # 练习: 手机号以110开头的作者出版过的所有书籍名称以及书籍出版社名称
    
        # 方式1:
        # 需求: 通过Book表join AuthorDetail表, Book与AuthorDetail无关联,所以必需连续跨表
        # ret=Book.objects.filter(authors__authordetail__telephone__startswith="110").values("title","publish__name")
        # print(ret)
        #
        # # 方式2:
        # ret=Author.objects.filter(authordetail__telephone__startswith="110").values("book__title","book__publish__name")
        # print(ret)
    
    # -------------------------聚合与分组查询---------------------------
        from django.db.models import Avg,Max,Min,Count
    #
    #     r# -------------------------聚合与分组查询---------------------------
    #
    #
    #     # ------------------------->聚合 aggregate:返回值是一个字典,不再是queryset
    #
    #     # 查询所有书籍的平均价格
    #     from django.db.models import Avg, Max, Min, Count
    #
    #     ret = Book.objects.all().aggregate(avg_price=Avg("price"), max_price=Max("price"))
    #     print(ret)  # {'avg_price': 151.0, 'max_price': Decimal('301.00')}
    #
    #     # ------------------------->分组查询 annotate ,返回值依然是queryset
    #
    #
    #     # ------------------------->单表分组查询:
    #
    #     # 示例1
    #     # 查询每一个部门的名称以及员工的平均薪水
    #
    #     # select dep,Avg(salary) from emp group by dep
    #
    #     # ret=Emp.objects.values("dep").annotate(avg_salary=Avg("salary"))
    #     # print(ret) # <QuerySet [{'avg_salary': 5000.0, 'dep': '保安部'}, {'avg_salary': 51000.0, 'dep': '教学部'}]>
    #
    #     # 单表分组查询的ORM语法: 单表模型.objects.values("group by的字段").annotate(聚合函数("统计字段"))
    #
    #     # 示例2
    #     # 查询每一个省份的名称以及员工数
    #
    #     # ret=Emp.objects.values("province").annotate(c=Count("id"))
    #     #
    #     # print(ret) # <QuerySet [{'province': '山东省', 'c': 2}, {'province': '河北省', 'c': 1}]>
    #
    #     # 补充知识点:
    #
    #     # ret=Emp.objects.all()
    #     # print(ret)  # select * from emp
    #     # ret=Emp.objects.values("name")
    #     # print(ret)  # select name from emp
    #     #
    #     # Emp.objects.all().annotate(avg_salary=Avg("salary"))
    #
    #
    #     # ------------------------->多表分组查询:
    #
    #     ## 示例1 查询每一个出版社的名称以及出版的书籍个数
    #
    #     ret = Publish.objects.values("nid").annotate(c=Count("book__title"))
    #     print(ret)  # <QuerySet [{'nid': 1, 'c': 3}, {'nid': 2, 'c': 1}]>
    #
    #     ret = Publish.objects.values("name").annotate(c=Count("book__title"))
    #     print(ret)  # <QuerySet [{'name': '人民出版社', 'c': 3}, {'name': '南京出版社', 'c': 1}]>
    #
    #     ret = Publish.objects.values("nid").annotate(c=Count("book__title")).values("name", "c")
    #     print(ret)  # <QuerySet [{'name': '人民出版社', 'c': 3}, {'name': '南京出版社', 'c': 1}]>
    #
    #     ## 示例2 查询每一个作者的名字以及出版过的书籍的最高价格
    #     ret = Author.objects.values("pk").annotate(max_price=Max("book__price")).values("name", "max_price")
    #     print(ret)
    #
    #     # 总结 跨表的分组查询的模型:
    #     # 每一个后表模型.objects.values("pk").annotate(聚合函数(关联表__统计字段))
    #
    #     # 示例3 查询每一个书籍的名称以及对应的作者个数
    #     ret = Book.objects.values("pk").annotate(c=Count("authors__name")).values("title", "c")
    #     print(ret)
    #
    #     #################### 跨表分组查询的另一种玩法  ####################
    #
    #     # 示例1 查询每一个出版社的名称以及出版的书籍个数
    #     # ret=Publish.objects.values("nid").annotate(c=Count("book__title")).values("name","email","c")
    #     # ret=Publish.objects.all().annotate(c=Count("book__title")).values("name","c","city")
    #     ret=Publish.objects.annotate(c=Count("book__title")).values("name","c","city")
    #     print(ret)
    #
    #     ##################### 练习   ####################
    #
    #     # 统计每一本以py开头的书籍的作者个数:
    #
    #     # 每一个后的表模型.objects.values("pk").annotate(聚合函数(关联表__统计字段)).values("表模型的所有字段以及统计字段")
    #     ret=Book.objects.filter(title__startswith="py").values("pk").annotate(c=Count("authors__name")).values("title","c")
    #
    #     # 统计不止一个作者的图书
    #     ret=Book.objects.values("pk").annotate(c=Count("authors__name")).filter(c__gt=1).values("title","c")
    #     print(ret)
    
    
    # ------------------------- F查询与Q查询-----------------------
    from django.db.models import F
    from django.db.models import Q
    # ------------F查询------------------
    #
    # F()可以比较同一model中不同字段的值。
    
    # 查询评论数大于收藏数的书籍
       from django.db.models import F
       Book.objects.filter(commnetNum__lt=F('keepNum'))
    
    #------------Q查询------------------
    # filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR 语句),你可以使用Q 对象
    # 示例:
    
    #1 bookList=Book.objects.filter(Q(authors__name="yuan")|Q(authors__name="egon"))
    """
    等同于下面的SQL WHERE 子句:
      WHERE name ="yuan" OR name ="egon"
    """"
    # 2 Q 对象可以使用& 和 |操作符组合起来 ,~ 操作符取反
    # bookList=Book.objects.filter(Q(authors__name="yuan")|Q(authors__name="egon"))
    # bookList=Book.objects.filter(Q(authors__name="yuan") & ~Q(publishDate__year=2017)).values_list("title")
    
    # 3查询函数可以混合使用Q 对象和关键字参数.所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。但是,如果出现Q 对象,它必须位于所有关键字参数的前面。例如:
    # bookList=Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017),
    #                               title__icontains="python")
    多表查询
    from django.shortcuts import render,HttpResponse
    
    # Create your views here.
    from app01.models import Book
    def index(request):
        # 添加表记录
    
        # # 批量导入
        # book_list=[]
        # for i in range(100):
        #     book = Book(title='book_%s'%i,price=i*i)
        #     book_list.append(book)
        # Book.objects.bulk_create(book_list)
    
        # 方式一
        # book_obj =Book(id =1,title='python',price=100,pub_date='2017-2-3',publish='人民出版社')
        # book_obj.save()
    
        # 方式二 create返回值就是当前生成的对象记录
        # book_obj =Book.objects.create(title='php',price=200,pub_date='2017-3-3',publish='人民出版社')
        # print(book_obj.title)
        # print(book_obj.price)
        # print(book_obj.pub_date)
    
    
        ############################ 查询表记录 #####################
        """
        1 方法的返回值
        2 方法的调用者
    
        """
        #(1)all方法: 返回值是一个queryset对象
        # book_list = Book.objects.all()
        # # print(book_list)  #数据类型:QuerySet [obj1,obj2,]
        # for obj in book_list:
        #     print(obj.title,obj.price)
    
        #(2) first,last :调用者:Queryset对象 返回值:model对象
        # book = Book.objects.all().first()
        # book = Book.objects.all().[0]
        # book = Book.objects.all().last()
    
        #(3) filter() 返回值:queryset对象
        # book_list= Book.objects.filter(price=100,title='go')
        # print(book_list)
    
        #(4) get() 有且只有一个查询结果时才有意义,返回值:model对象
    
        # Book.objects.get(title='python')
    
        #<5> exclude():  它包含了与所给筛选条件不匹配的对象(queryset对象)
        # ret= Book.objects.exclude(title='go')
        # <6> : 对查询结果排序
        # ret =Book.objects.all().order_by('id') #升序
        # ret =Book.objects.all().order_by('-id') #降序
    
        # <7> count(): 返回数据库中匹配查询(QuerySet)的对象数量。返回值:int类型
        # ret = Book.objects.all().count()
        # print(ret)
    
        # <8> exists(): 如果QuerySet包含数据,就返回True,否则返回False
        # ret = Book.objects.all().exists()
    
        # <9> values(*field):返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列
        #                             model的实例化对象,而是一个可迭代的字典序列
        # ret = Book.objects.all()
        # for i in ret:
        #     print(i.title)
        #
        # ret= Book.objects.all().values('price')
        # print(ret)
    
        # <10> values_list(*field): 它与values()
        # 非常相似,它返回的是一个元组序列,values返回的是一个字典序列
        # ret= Book.objects.all().values('price','title')
    
        # <14> distinct(): 从返回结果中剔除重复纪录
        # ret =Book.objects.all().values('price').distinct()
        # print(ret)
    
        ########################### 查询表记录-模糊查询 #####################
        # ret =Book.objects.filter(price__gt=100) # 大于
        # ret =Book.objects.filter(price__lt=200) # 小于
        # print(ret)
    
        # ret=Book.objects.filter(title__startswith='p')
        # print(ret)
    
        # ret =Book.objects.filter(title__contains='p')
        # ret =Book.objects.filter(title__icontains='p') # 不区分大小写
        # print(ret)
    
        # ret = Book.objects.filter(price__in=[100,200])
        # print(ret)
        # ret=Book.objects.filter(pub_date__year=2012)
        # print(ret)
    
    
        ########################### 查询表记录-删除和修改记录 #####################
    
        # delect/update :调用者:是一个 queryset对象 model对象
        ret = Book.objects.filter(price=300).delete()
        # ret = Book.objects.filter(price=200).first().delete() ##
    
        # ret2 =Book.objects.filter(title='python').update(title='ppy')
        print(ret,type(ret))
    
        return HttpResponse('Ok')
    
    def query(request):
    # # 1
    # # 查询老男孩出版社出版过的价格大于200的书籍
    #     ret =Book.objects.filter(publish='老男孩出版社',price__gt=200)
    #
    # # 2
    # # 查询2017年8月出版的所有以py开头的书籍名称
    #     ret2 = Book.objects.filter(pub_date__year=2017,pub_date__day=8,title__startswith='py').values('title')
    # # 3
    # # 查询价格为50, 100或者150的所有书籍名称及其出版社名称
    #     ret3 =Book.objects.filter(price__in=[50,100,150]).values('title','publish')
    # # 4
    # # 查询价格在100到200之间的所有书籍名称及其价格
    #     ret4 =Book.objects.filter(price__range=[100,200]).values('title','price')
    # # 5
    # # 查询所有人民出版社出版的书籍的价格(从高到低排序,去重)
    #     ret5=Book.objects.filter(publish='人民出版社').values('price').distinct().order_by('-price')
        return HttpResponse('ok')
    单表查询(批量添加记录)
    ---查询:
    
    日期归档查询
    
       1    date_format
    
            ============date,time,datetime===========
    
            create table t_mul_new(d date,t time,dt datetime);
    
            insert into t_mul_new values(now(),now(),now());
    
            select * from t_mul;
    
    
            mysql> select * from t_mul;
            +------------+----------+---------------------+
            | d          | t        | dt                  |
            +------------+----------+---------------------+
            | 2017-08-01 | 19:42:22 | 2017-08-01 19:42:22 |
            +------------+----------+---------------------+
            1 row in set (0.00 sec)
    
    
            select date_format(dt,"%Y/%m/%d") from t_mul;
    
    
       2  extra (在orm中使用sql语句)
    
            extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
    
            有些情况下,Django的查询语法难以简单的表达复杂的 WHERE 子句,对于这种情况, Django 提供了 extra() QuerySet修改机制 — 它能在 QuerySet生成的SQL从句中注入新子句
    
            extra可以指定一个或多个 参数,例如 select, where or tables. 这些参数都不是必须的,但是你至少要使用一个!要注意这些额外的方式对不同的数据库引擎可能存在移植性问题.(因为你在显式的书写SQL语句),除非万不得已,尽量避免这样做
    
            参数之select
    
            The select 参数可以让你在 SELECT 从句中添加其他字段信息,它应该是一个字典,存放着属性名到 SQL 从句的映射。
    
            queryResult=models.Article
                       .objects.extra(select={'is_recent': "create_time > '2017-09-05'"})
            结果集中每个 Entry 对象都有一个额外的属性is_recent, 它是一个布尔值,表示 Article对象的create_time 是否晚于2017-09-05.
    
            练习:
    
            in sqlite:
    
                article_obj=models.Article.objects
                          .extra(select={"standard_time":"strftime('%%Y-%%m-%%d',create_time)"})
                          .values("standard_time","nid","title")
                print(article_obj)
                # <QuerySet [{'title': 'MongoDb 入门教程', 'standard_time': '2017-09-03', 'nid': 1}]>
    
    
       3 日期归档查询的方式2
    
           from django.db.models.functions import TruncMonth
    
           Sales.objects
                .annotate(month=TruncMonth('timestamp'))  # Truncate to month and add to select list
                .values('month')                          # Group By month
                .annotate(c=Count('id'))                  # Select the count of the grouping
                .values('month', 'c')                     # (might be redundant, haven't tested) select month and count
    orm&sql&日期

    4 Cookie-Session

    from django.shortcuts import render,HttpResponse,redirect
    
    from app01.models import UserInfo
    # Create your views here.
    
    
    
    def login(request):
        """
        # 设置cookie
         response.set_cookie('is_login',True)
        """
        if request.method=='POST':
            response =HttpResponse('登陆成功!!')
            response.set_cookie('is_login',True)
            response.set_cookie('username',request.POST.get('user'))
            # import datetime
            # date=datetime.datetime(year=2019,month=5,day=29,hour=14,minute=34) # 设置过期时间
            # response.set_cookie("username",user.user,expires=date)
            return response
    
        return render(request,'login.html')
    
    
    def index(request):
        """
        # 获取COOKIES
        is_login= request.COOKIES.get('is_login')
        """
        print("index:", request.COOKIES)
        is_login= request.COOKIES.get('is_login')
        if is_login:
            username =request.COOKIES.get('username')
    
            import datetime
    
            now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            last_visit_time = request.COOKIES.get("last_visit_time", "")
            response = render(request, "index.html", {"username": username, "last_visit_time": last_visit_time})
            response.set_cookie("last_visit_time", now)
            return response
        else:
            return redirect("/login/")
    
    # session
    def login_session(request):
        """
       设置session
       request.session["username"] = user_obj.user
        """
        if request.method=='POST':
            user = request.POST.get('user')
            pwd = request.POST.get('pwd')
            user_obj =UserInfo.objects.filter(user=user,pwd=pwd).first()
    
            if user_obj:
                import datetime
    
                now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                request.session["is_login"] = True
                request.session["username"] = user_obj.user
                request.session["last_visit_time"] = now
                return HttpResponse("登录成功!")
    
        return render(request,'login.html')
    
    def index_session(request):
        """
        获取session
         is_login = request.session.get("is_login")
        """
        print("is_login:", request.session.get("is_login"))
        is_login = request.session.get("is_login")
        if not is_login:
            return redirect("/login_session/")
    
        username = request.session.get("username")
        last_visit_time = request.session.get("last_visit_time")
    
        return render(request, "index.html", {"username": username, "last_visit_time": last_visit_time})
    
    
    def logout(request):
        """
        删除session
        request.session.flush()
        """
        # del request.session["is_login"]
    
        request.session.flush() #删除当前的会话数据并删除会话的Cookie。
    
        '''
        1 randon_str=request.COOKIE.get("sessionid")
    
        2 django-session.objects.filter(session-key=randon_str).delete()
    
        3 response.delete_cookie("sessionid",randon_str)
    
        '''
    
        return redirect("/login/")
    cookie-session

    5 用户认证组件

    from django.shortcuts import render,HttpResponse,redirect
    
    # Create your views here.
    
    from django.contrib import auth
    from django.contrib.auth.models import User
    from django.contrib.auth.decorators import login_required
    
    def login(request):
    
        if request.method == "POST":
            user = request.POST.get("user")
            pwd = request.POST.get("pwd")
    
            # if 验证成功返回user对象,否则返回None
            user=auth.authenticate(username=user,password=pwd)
    
            if user:
                auth.login(request,user)   # request.user:当前登录对象
    
                next_url=request.GET.get("next","/index/")
                return  redirect(next_url)
    
    
        return render(request,"login.html")
    
    
    
    @login_required
    def index(request):
    
        # print("request.user:",request.user.username)
        # print("request.user:",request.user.id)
        # print("request.user:",request.user.is_anonymous)
        #
        # #if request.user.is_anonymous:
        # if not request.user.is_authenticated:
        #     return redirect("/login/")
    
        #username=request.user.username
        #return render(request,"index.html",{"username":username})
    
        return render(request,"index.html")
    
    
    @login_required
    def order(request):
    
        # if not request.user.is_authenticated:
        #     return redirect("/login/")
    
    
        return render(request,"order.html")
    
    
    
    
    
    
    
    def logout(request):
    
        auth.logout(request) #当调用该函数时,当前请求的session信息会全部清除
    
        return redirect("/login/")
    
    
    
    
    def reg(request):
        """
        注册
        """
        if request.method=="POST":
            user = request.POST.get("user")
            pwd = request.POST.get("pwd")
    
            #User.objects.create(username=user,password=pwd)
            user=User.objects.create_user(username=user,password=pwd)
    
            return redirect("/login/")
    
    
        return render(request,"reg.html")
    用户认证组件.py
        用户认证组件:
    
             功能:用session纪录登陆验证状态
    
             前提:用户表:dajngo自带的auth_user
             
             创建超级用户:python3 manage.py createsuperuser
    
    
             API:
                from django.contrib import auth :
    
                    1 # if 验证成功返回user对象,否则返回None                            
                       user=auth.authenticate(username=user,password=pwd)    
    
                     2 auth.login(request,user)   # request.user:当前登录对象 
    
                     3 auth.logout(request)    
    
                from django.contrib.auth.models import User # User==auth_user
    
                    4 request.user.is_authenticated() 
    
                    5 user = User.objects.create_user(username='',password='',email='')
    
    
                补充:
                   匿名用户对象:
                        匿名用户
                        class models.AnonymousUser
    
                        django.contrib.auth.models.AnonymousUser 类实现了django.contrib.auth.models.User 接口,但具有下面几个不同点:
    
                        id 永远为None。
                        username 永远为空字符串。
                        get_username() 永远返回空字符串。
                        is_staff 和 is_superuser 永远为False。
                        is_active 永远为 False。
                        groups 和 user_permissions 永远为空。
                        is_anonymous() 返回True 而不是False。
                        is_authenticated() 返回False 而不是True。
                        set_password()、check_password()、save() 和delete() 引发 NotImplementedError。
                        New in Django 1.8:
                        新增 AnonymousUser.get_username() 以更好地模拟 django.contrib.auth.models.User。
    
    
                总结:
    
                     
                         if not: auth.login(request,user)   request.user == AnonymousUser()
    
                         else:request.user==登录对象
                         request.user是一个全局变量
    
                         在任何视图和模板直接使用
    补充-说明

    6 forms组件

    from django.shortcuts import render,HttpResponse
    
    # Create your views here.
    from django import forms
    from django.forms import widgets
    
    wid_01=widgets.TextInput(attrs={"class":"form-control"})
    wid_02=widgets.PasswordInput(attrs={"class":"form-control"})
    class UserForm(forms.Form):
        name=forms.CharField(min_length=4,label='用户名',widget=wid_01,error_messages={"required":"该字段不能为空"})
        pwd=forms.CharField(min_length=4,label='密码',widget=wid_02)
        r_pwd=forms.CharField(min_length=4,widget=wid_01)
        email = forms.EmailField(label='邮箱',widget=wid_01,error_messages={"required":"该字段不能为空","invalid":"格式错误"},)
    
    
    def reg(request):
        if request.method=='POST':
            # print(request.POST)
            form =UserForm(request.POST)
            print(form.is_valid()) # 返回布尔值
    
            if form.is_valid():
                print(form.cleaned_data)  # 所有干净的字段以及对应的值
            else:
                print(form.cleaned_data)
                print(form.errors)  # ErrorDict : {"校验错误的字段":["错误信息",]}
    
                print(form.errors.get("name"))  # ErrorList ["错误信息",]
                print(form.errors.get("name")[0])  # ErrorList ["错误信息",]
    
                return render(request, 'reg.html', locals())
    
    
    
        form =UserForm()
        return render(request,'reg.html',locals())
    forms渲染页面-检验字段
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
         <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
        <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    </head>
    <body>
    <form action="" method="post">
        {% csrf_token %}
        <div>
            <label for="user">用户名</label>
            <p><input type="text" name="name" id="name"></p>
        </div>
        <div>
            <label for="pwd">密码</label>
            <p><input type="password" name="pwd" id="pwd"></p>
        </div>
        <div>
            <label for="r_pwd">确认密码</label>
            <p><input type="password" name="r_pwd" id="r_pwd"></p>
        </div>
         <div>
            <label for="email">邮箱</label>
            <p><input type="text" name="email" id="email"></p>
        </div>
        <input type="submit">
    </form>
    
    <hr>
    <h3>form组件渲染方式1</h3>
    <div class="container">
        <div class="row">
            <div class="col-md-6 col-lg-offset-3">
    
                    <form action="" method="post">
                        {% csrf_token %}
                        <div>
                            <label for="">用户名</label>
                            {{ form.name }}
                        </div>
                        <div>
                            <label for="">密码</label>
                            {{ form.pwd }}
                        </div>
                        <div>
                            <label for="">确认密码</label>
                            {{ form.r_pwd }}
                        </div>
                        <div>
                            <label for=""> 邮箱</label>
                            {{ form.email }}
                        </div>
    
                        <input type="submit" class="btn btn-default pull-right">
                    </form>
            </div>
        </div>
    </div>
    
    <h3>forms组件渲染方式2</h3>
                <form action="" method="post" novalidate>
                     {% csrf_token %}
                    {% for field in form %}
                        <div>
                            <label for="">{{ field.label }}</label>
                            {{ field }} <span class="pull-right" style="color: red">{{ field.errors.0 }}</span>
                        </div>
                    {% endfor %}
    
                     <input type="submit">
                </form>
    
    <hr>
    <p>不建议用,测试可使用</p>
     <h3>forms组件渲染方式3</h3>
                <form action="" method="post">
                     {% csrf_token %}
    
                     {{ form.as_p }}
    
                     <input type="submit">
                </form>
    
    </body>
    </html>
    forms渲染页面.html
    from django import forms
    
    from django.forms import widgets
    from app01.models import UserInfo
    
    from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
    
    class UserForm(forms.Form):
        name=forms.CharField(min_length=4,label="用户名",error_messages={"required":"该字段不能为空"},
                             widget=widgets.TextInput(attrs={"class":"form-control"})
                             )
        pwd=forms.CharField(min_length=4,label="密码",
                            widget=widgets.PasswordInput(attrs={"class":"form-control"})
                            )
        r_pwd=forms.CharField(min_length=4,label="确认密码",error_messages={"required":"该字段不能为空"},widget=widgets.TextInput(attrs={"class":"form-control"}))
        email=forms.EmailField(label="邮箱",error_messages={"required":"该字段不能为空","invalid":"格式错误"},widget=widgets.TextInput(attrs={"class":"form-control"}))
        tel=forms.CharField(label="手机号",widget=widgets.TextInput(attrs={"class":"form-control"}))
    
    
        def clean_name(self):
    
            val=self.cleaned_data.get("name")
    
            ret=UserInfo.objects.filter(name=val)
    
            if not ret:
                return val
            else:
                raise ValidationError("该用户已注册!")
    
        def clean_tel(self):
    
            val=self.cleaned_data.get("tel")
    
            if len(val)==11:
    
                return val
            else:
                raise  ValidationError("手机号格式错误")
    
        def clean(self):
            pwd=self.cleaned_data.get('pwd')
            r_pwd=self.cleaned_data.get('r_pwd')
    
            if pwd and r_pwd:
                if pwd==r_pwd:
                    return self.cleaned_data
                else:
                    raise ValidationError('两次密码不一致')
            else:
    
                return self.cleaned_data
    myforms全局与局部钩子

    7 ajax示例 &文件上传

    13.1 基于jquery的Ajax实现
    <button class="send_Ajax">send_Ajax</button>
    <script>
           $(".send_Ajax").click(function(){
               $.ajax({
                   url:"/handle_Ajax/",
                   type:"POST",
                   data:{username:"Yuan",password:123},
                   success:function(data){
                       console.log(data)
                   },
                   
                   error: function (jqXHR, textStatus, err) {
                            console.log(arguments);
                        },
                   complete: function (jqXHR, textStatus) {
                            console.log(textStatus);
                    },
                   statusCode: {
                        '403': function (jqXHR, textStatus, err) {
                              console.log(arguments);
                         },
                        '400': function (jqXHR, textStatus, err) {
                            console.log(arguments);
                        }
                    }
               })
           })
    </script>
    
    13.2 基于form表单的文件上传
    模板部分
    
    <form action="" method="post" enctype="multipart/form-data">
          用户名 <input type="text" name="user">
          头像 <input type="file" name="avatar">
        <input type="submit">
    </form>
    视图部分
    
    def index(request):
        print(request.body)   # 原始的请求体数据
        print(request.GET)    # GET请求数据
        print(request.POST)   # POST请求数据
        print(request.FILES)  # 上传的文件数据
        return render(request,"index.html")
    
    13.3 基于Ajax的文件上传
    模板
    
    <form>
          用户名 <input type="text" id="user">
          头像 <input type="file" id="avatar">
         <input type="button" id="ajax-submit" value="ajax-submit">
    </form>
    
    <script>
    
        $("#ajax-submit").click(function(){
            var formdata=new FormData();
            formdata.append("user",$("#user").val());
            formdata.append("avatar_img",$("#avatar")[0].files[0]);
            $.ajax({
    
                url:"",
                type:"post",
                data:formdata,
                processData: false ,    // 不处理数据
                contentType: false,    // 不设置内容类型
    
                success:function(data){
                    console.log(data)
                }
            })
        })
    </script>
    视图
    
    def index(request):
        if request.is_ajax():
            print(request.body)   # 原始的请求体数据
            print(request.GET)    # GET请求数据
            print(request.POST)   # POST请求数据
            print(request.FILES)  # 上传的文件数据
            return HttpResponse("ok")
        return render(request,"index.html")
    
    检查浏览器的请求头:
    
    Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryaWl9k5ZMiTAzx3FT
    ajax-文件上传

    8 分页器

    from django.shortcuts import render
    
    # Create your views here.
    
    
    from .models import Book
    
    from django.core.paginator import Paginator,EmptyPage
    
    def index(request):
        '''
        批量导入:
        book_list=[]
        for i in range(100):
            book=Book(title="book_%s"%i,price=i*i)
            book_list.append(book)
    
        Book.objects.bulk_create(book_list)
        :param request:
        :return:
        '''
    
    
        book_list=Book.objects.all()
    
        # 分页器
    
        paginator=Paginator(book_list,10)
    
        print("count:",paginator.count)           #数据总数
        print("num_pages",paginator.num_pages)    #总页数
        print("page_range",paginator.page_range)  #页码的列表
    
        current_page_num=int(request.GET.get("page",1))
    
        if paginator.num_pages>11:
    
            if current_page_num-5<1:
                page_range=range(1,12)
            elif current_page_num+5>paginator.num_pages:
                page_range=range(paginator.num_pages-10,paginator.num_pages+1)
    
            else:
                page_range=range(current_page_num-5,current_page_num+6)
        else:
            page_range=paginator.page_range
    
    
    
        try:
    
    
            current_page=paginator.page(current_page_num)
    
            # 显示某一页具体数据的两种方式:
            print("object_list",current_page.object_list)
            for i in current_page:
                print(i)
    
        except EmptyPage as e:
             current_page=paginator.page(1)
    
    
        return render(request,"index.html",locals())
    分页.py
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
        <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    </head>
    <body>
    
    
    
    <ul>
        {% for book in current_page %}
        <li>{{ book.title }}:{{ book.price }}</li>
        {% endfor %}
    
    </ul>
    
    
    <nav aria-label="Page navigation">
      <ul class="pagination">
        {% if current_page.has_previous %}
        <li><a href="?page={{ current_page.previous_page_number  }}" aria-label="Previous"><span aria-hidden="true">上一页</span></a></li>
        {% else %}
        <li class="disabled"><a href="" aria-label="Previous"><span aria-hidden="true">上一页</span></a></li>
        {% endif %}
    
    
    
        {% for item in page_range %}
            
            {% if current_page_num == item %}
                <li class="active"><a href="?page={{ item }}">{{ item }}</a></li>
            {% else %}
                <li><a href="?page={{ item }}">{{ item }}</a></li>
            {% endif %}
    
        {% endfor %}
    
    
    
        {% if current_page.has_next %}
            <li><a href="?page={{ current_page.next_page_number  }}" aria-label="Next"><span aria-hidden="true">下一页</span></a>
        {% else %}
                    <li class="disabled"><a href="" aria-label="Next"><span aria-hidden="true">下一页</span></a>
        {% endif %}
    </li>
      </ul>
    </nav>
    
    </body>
    </html>
    分页展示.html

    9 中间件

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    
    class CustomerMiddleware(MiddlewareMixin):
    
        def process_request(self,request):
            print("CustomerMiddleware1 process_request....")
    
            #return HttpResponse("forbidden....")
    
    
        def process_response(self,request,response):
            print("CustomerMiddleware1 process_response")
    
            return response
            #return HttpResponse("hello yuan")
    
        def process_view(self, request, callback, callback_args, callback_kwargs):
            print("CustomerMiddleware1 process_view")
    
    
        def process_exception(self, request, exception):
    
            print("CustomerMiddleware1 process_exception")
            return HttpResponse(exception)
    
    
    
    
    class CustomerMiddleware2(MiddlewareMixin):
    
        def process_request(self,request):
            print("CustomerMiddleware2 process_request....")
    
        def process_response(self,request,response):
            print("CustomerMiddleware2 process_response")
            return response
    
        def process_view(self, request, callback, callback_args, callback_kwargs):
            # print("====>",callback(callback_args))
            print("CustomerMiddleware2 process_view")
            # ret=callback(callback_args)
            # return ret
    
        def process_exception(self, request, exception):
    
            print("CustomerMiddleware2 process_exception")
    
            #return HttpResponse(exception)
    my_middlewares.py
    1 在setting 中注册中间件
    例如:
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
        #新注册的
        "app01.my_middlewares.CustomerMiddleware",
        "app01.my_middlewares.CustomerMiddleware2"
    
    ]
    2 在app01/my_middleearee.py中编写中间件逻辑
    
    中间件中一共有四个方法:
    process_request
           权限认证,白名单,登录认证。。
    process_view
           csrf_toke认证
    process_exception
    process_response
        drf 解决跨域问题
    中间件使用.txt

    10 事务操作&发邮件

     
    
    1 事务操作(多件事情保持原子性:共进退)
    示例:
    from django.db import transaction
    with transaction.atomic():  # 添加事务(保证两个操作共同进行)
            comment_obj = Comment.objects.create(user_id=user_id, content=content, article_id=article_id,
                                                 parent_comment_id=pid)
            Article.objects.filter(pk=article_id).update(comment_count=F('comment_count') + 1)
    
    2发邮件
    settings.py
    # 发送邮件配置
    EMAIL_HOST = 'smtp.qq.com'  # 如果是 163 改成 smtp.163.com
    EMAIL_PORT = 465  # 163---25
    EMAIL_HOST_USER = '1485571783@qq.com'  # 帐号
    EMAIL_HOST_PASSWORD = 'wzjotnnanlyhbafg'  # IMAP/SMTP服务 密码
    # EMAIL_HOST_PASSWORD = 'omurtfcglkuahfdi'  # 密码
    DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
    EMAIL_USE_SSL = True
    
    views.py
     # 发送邮件
        from django.core.mail import send_mail
        from cnblog import settings
        from threading import Thread
    
        t =Thread(target=send_mail, args=('您的文章%s新增了一条评论内容' % (article_obj.title),
                                       content,
                                       settings.EMAIL_HOST_USER,
                                       ['huawang400@gmail.com'],))
        t.start()
        # send_mail(
        #     '您的文章%s新增了一条评论内容' % (article_obj.title),
        #     content,
        #     settings.EMAIL_HOST_USER,
        #     ['huawang400@gmail.com'],
        # )
    
    应用:cnblog下的文章详情页下的评论功能使用
    事务操作&发邮件

    11 基于admin组件录入数据

    from django.contrib import admin
    
    # Register your models here.
    from . import models
    
    for table in models.__all__:
        admin.site.register(getattr(models, table))
    admin.py
    from django.db import models
    # Create your models here.
    
    from django.db import models
    from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
    from django.contrib.contenttypes.models import ContentType
    
    # Create your models here.
    __all__ = ["Category", "Course", "CourseDetail", "Teacher", "DegreeCourse", "CourseChapter",
               "CourseSection", "PricePolicy", "OftenAskedQuestion", "Comment", "Account", "CourseOutline"]
    
    
    class Category(models.Model):
        """课程分类表"""
        title = models.CharField(max_length=32, unique=True, verbose_name="课程的分类")
    
        def __str__(self):
            return self.title
    
        class Meta:
            verbose_name = "01-课程分类表"
            db_table = verbose_name # 上线去掉
            verbose_name_plural = verbose_name
    
    
    class Course(models.Model):
        """课程表"""
        title = models.CharField(max_length=128, unique=True, verbose_name="课程的名称")
        course_img = models.ImageField(upload_to="course/%Y-%m", verbose_name='课程的图片')
        category = models.ForeignKey(to="Category", verbose_name="课程的分类", on_delete=None)
    
    
        COURSE_TYPE_CHOICES = ((0, "付费"), (1, "vip专享"), (2, "学位课程"))
        course_type = models.SmallIntegerField(choices=COURSE_TYPE_CHOICES)
        degree_course = models.ForeignKey(to="DegreeCourse", blank=True, null=True, help_text="如果是学位课程,必须关联学位表", on_delete=None)
    
    
        brief = models.CharField(verbose_name="课程简介", max_length=1024)
        level_choices = ((0, '初级'), (1, '中级'), (2, '高级'))
        level = models.SmallIntegerField(choices=level_choices, default=1)
    
        status_choices = ((0, '上线'), (1, '下线'), (2, '预上线'))
        status = models.SmallIntegerField(choices=status_choices, default=0)
        pub_date = models.DateField(verbose_name="发布日期", blank=True, null=True)
    
        order = models.IntegerField("课程顺序", help_text="从上一个课程数字往后排")
        study_num = models.IntegerField(verbose_name="学习人数", help_text="只要有人买课程,订单表加入数据的同时给这个字段+1")
    
        # order_details = GenericRelation("OrderDetail", related_query_name="course")
        # coupon = GenericRelation("Coupon")
        # 只用于反向查询不生成字段
        price_policy = GenericRelation("PricePolicy")
        often_ask_questions = GenericRelation("OftenAskedQuestion")
        course_comments = GenericRelation("Comment")
    
        def save(self, *args, **kwargs):
            if self.course_type == 2:
                if not self.degree_course:
                    raise ValueError("学位课必须关联学位课程表")
            super(Course, self).save(*args, **kwargs)
    
        def __str__(self):
            return self.title
    
        class Meta:
            verbose_name = "02-课程表"
            db_table = verbose_name
            verbose_name_plural = verbose_name
    
    
    class CourseDetail(models.Model):
        """课程详细表"""
        course = models.OneToOneField(to="Course", on_delete=None)
        hours = models.IntegerField(verbose_name="课时", default=7)
        course_slogan = models.CharField(max_length=125, blank=True, null=True, verbose_name="课程口号")
        video_brief_link = models.CharField(max_length=255, blank=True, null=True)
        summary = models.TextField(max_length=2048, verbose_name="课程概述")
        why_study = models.TextField(verbose_name="为什么学习这门课程")
        what_to_study_brief = models.TextField(verbose_name="我将学到哪些内容")
        career_improvement = models.TextField(verbose_name="此项目如何有助于我的职业生涯")
        prerequisite = models.TextField(verbose_name="课程先修要求", max_length=1024)
        recommend_courses = models.ManyToManyField("Course", related_name="recommend_by", blank=True)
    
        teachers = models.ManyToManyField("Teacher", verbose_name="课程讲师")
    
        def __str__(self):
            return self.course.title
    
        class Meta:
            verbose_name = "03-课程详细表"
            db_table = verbose_name
            verbose_name_plural = verbose_name
    
    
    class Teacher(models.Model):
        """讲师表"""
        name = models.CharField(max_length=32, verbose_name="讲师名字")
        brief = models.TextField(max_length=1024, verbose_name="讲师介绍")
    
        def __str__(self):
            return self.name
    
        class Meta:
            verbose_name = "04-教师表"
            db_table = verbose_name
            verbose_name_plural = verbose_name
    
    
    class DegreeCourse(models.Model):
        """
        字段大体跟课程表相同,哪些不同根据业务逻辑去区分
        """
        title = models.CharField(max_length=32, verbose_name="学位课程名字")
    
        def __str__(self):
            return self.title
    
        class Meta:
            verbose_name = "05-学位课程表"
            db_table = verbose_name
            verbose_name_plural = verbose_name
    
    
    class CourseChapter(models.Model):
        """课程章节表"""
        course = models.ForeignKey(to="Course", related_name="course_chapters", on_delete=None)
        chapter = models.SmallIntegerField(default=1, verbose_name="第几章")
        title = models.CharField(max_length=32, verbose_name="课程章节名称")
    
        def __str__(self):
            return self.title
    
        class Meta:
            verbose_name = "06-课程章节表"
            db_table = verbose_name
            verbose_name_plural = verbose_name
            unique_together = ("course", "chapter")
    
    
    class CourseSection(models.Model):
        """课时表"""
        chapter = models.ForeignKey(to="CourseChapter", related_name="course_sections", on_delete=None)
        title = models.CharField(max_length=32, verbose_name="课时")
        section_order = models.SmallIntegerField(verbose_name="课时排序", help_text="建议每个课时之间空1至2个值,以备后续插入课时")
        section_type_choices = ((0, '文档'), (1, '练习'), (2, '视频'))
        free_trail = models.BooleanField("是否可试看", default=False)
        section_type = models.SmallIntegerField(default=2, choices=section_type_choices)
        section_link = models.CharField(max_length=255, blank=True, null=True, help_text="若是video,填vid,若是文档,填link")
    
        def course_chapter(self):
            return self.chapter.chapter
    
        def course_name(self):
            return self.chapter.course.title
    
        def __str__(self):
            return "%s-%s" % (self.chapter, self.title)
    
        class Meta:
            verbose_name = "07-课程课时表"
            db_table = verbose_name
            verbose_name_plural = verbose_name
            unique_together = ('chapter', 'section_link')
    
    
    class PricePolicy(models.Model):
        """价格策略表"""
        content_type = models.ForeignKey(ContentType, on_delete=None)  # 关联course or degree_course
        object_id = models.PositiveIntegerField()
        content_object = GenericForeignKey('content_type', 'object_id')
    
        valid_period_choices = ((1, '1天'), (3, '3天'),
                                (7, '1周'), (14, '2周'),
                                (30, '1个月'),
                                (60, '2个月'),
                                (90, '3个月'),
                                (120, '4个月'),
                                (180, '6个月'), (210, '12个月'),
                                (540, '18个月'), (720, '24个月'),
                                (722, '24个月'), (723, '24个月'),
                                )
        valid_period = models.SmallIntegerField(choices=valid_period_choices)
        price = models.FloatField()
    
        def __str__(self):
            return "%s(%s)%s" % (self.content_object, self.get_valid_period_display(), self.price)
    
        class Meta:
            verbose_name = "08-价格策略表"
            db_table = verbose_name
            verbose_name_plural = verbose_name
            unique_together = ("content_type", 'object_id', "valid_period")
    
    
    class OftenAskedQuestion(models.Model):
        """常见问题"""
        content_type = models.ForeignKey(ContentType, on_delete=None)  # 关联course or degree_course
        object_id = models.PositiveIntegerField()
        content_object = GenericForeignKey('content_type', 'object_id')
    
        question = models.CharField(max_length=255)
        answer = models.TextField(max_length=1024)
    
        def __str__(self):
            return "%s-%s" % (self.content_object, self.question)
    
        class Meta:
            verbose_name = "09-常见问题表"
            db_table = verbose_name
            verbose_name_plural = verbose_name
            unique_together = ('content_type', 'object_id', 'question')
    
    
    class Comment(models.Model):
        """通用的评论表"""
        content_type = models.ForeignKey(ContentType, blank=True, null=True, on_delete=None)
        object_id = models.PositiveIntegerField(blank=True, null=True)
        content_object = GenericForeignKey('content_type', 'object_id')
    
        content = models.TextField(max_length=1024, verbose_name="评论内容")
        account = models.ForeignKey("Account", verbose_name="会员名", on_delete=None)
        date = models.DateTimeField(auto_now_add=True)
    
        def __str__(self):
            return self.content
    
        class Meta:
            verbose_name = "10-评价表"
            db_table = verbose_name
            verbose_name_plural = verbose_name
    
    
    class Account(models.Model):
        username = models.CharField(max_length=32, verbose_name="用户姓名")
        pwd = models.CharField(max_length=32, verbose_name="密文密码")
        # head_img = models.CharField(max_length=256, default='/static/frontend/head_portrait/logo@2x.png',
        #                             verbose_name="个人头像")
        balance = models.IntegerField(verbose_name="贝里余额", default=0)
    
        def __str__(self):
            return self.username
    
        class Meta:
            verbose_name = "11-用户表"
            db_table = verbose_name
            verbose_name_plural = verbose_name
    
    
    class CourseOutline(models.Model):
        """课程大纲"""
        course_detail = models.ForeignKey(to="CourseDetail", related_name="course_outline", on_delete=None)
        title = models.CharField(max_length=128)
        order = models.PositiveSmallIntegerField(default=1)
        # 前端显示顺序
    
        content = models.TextField("内容", max_length=2048)
    
        def __str__(self):
            return "%s" % self.title
    
        class Meta:
            verbose_name = "12-课程大纲表"
            db_table = verbose_name
            verbose_name_plural = verbose_name
            unique_together = ('course_detail', 'title')
    models.py
    基于admin组件录入数据
    
    前期准备:
     创建超级用户:python manage.py createsuperuser
     访问:127.0.0.1/admin
    
    示例一:
    以项目下的course APP为例:
    1 模型层处理  (course/model.py)
    from django.db import models
    # Create your models here.
    
    from django.db import models
    
    # 将表名写入__all__
    __all__ = ["Category", "Course", "CourseDetail", "Teacher", "DegreeCourse", "CourseChapter",
               "CourseSection", "PricePolicy", "OftenAskedQuestion", "Comment", "Account", "CourseOutline"]
    2 admin下注册 ( course/admin.py)
    from django.contrib import admin
    
    # Register your models here.
    from . import models
    
    for table in models.__all__:
        admin.site.register(getattr(models, table))
    
    
    示例二:
    
    在blog/admin.py文件:
    
    from django.contrib import admin
    
    # Register your models here.
    from blog import models
    
    admin.site.register(models.UserInfo)
    admin.site.register(models.Blog)
    admin.site.register(models.Category)
    admin.site.register(models.Tag)
    admin.site.register(models.Article)
    admin.site.register(models.ArticleUpDown)
    admin.site.register(models.Article2Tag)
    admin.site.register(models.Comment)
    admin录入数据.txt

    12 inclution_tag&日期处理

    ----- inclution_tag的使用 (文章详情页与个人站点共用一套动态渲染的模板)
    应用:个人站点页面设计(ORM跨表与分组查询)
        1 inclution_tag的使用 (文章详情页与个人站点共用一套动态渲染的模板)
        2 orm查询中使用sql语句(extra方法的使用)
    
    
    使用:
    1 在当前应用app文件目录下--->创建一个templatetags文件夹----->创建一个py文件,比如my_tags.py
    2 my_tags.py 中自定义标签
    
    
    from django.db.models import Count
    from blog import models
    
    from django import template
    register=template.Library()
    
    @register.inclusion_tag("classification.html")
    def get_classification_style(username):
    
        user = models.UserInfo.objects.filter(username=username).first()
        blog = user.blog
    
        cate_list=models.Category.objects.filter(blog=blog).values("pk").annotate(c=Count("article__title")).values_list("title","c")
    
        tag_list=models.Tag.objects.filter(blog=blog).values("pk").annotate(c=Count("article")).values_list("title","c")
    
        date_list=models.Article.objects.filter(user=user).extra(select={"y_m_date":"date_format(create_time,'%%Y/%%m')"}).values("y_m_date").annotate(c=Count("nid")).values_list("y_m_date","c")
    
    
        return {"blog":blog,"cate_list":cate_list,"date_list":date_list,"tag_list":tag_list}
    
    3 在模板下创建classification.html文件
    # classification.html文件
     <div>
        <div class="panel panel-warning">
                    <div class="panel-heading">我的标签</div>
                    <div class="panel-body">
                        {% for tag in tag_list %}
                            <p><a href="/{{ username }}/tag/{{ tag.0 }}">{{ tag.0 }}({{ tag.1 }})</a></p>
                        {% endfor %}
    
                    </div>
                </div>
    
        <div class="panel panel-danger">
            <div class="panel-heading">随笔分类</div>
            <div class="panel-body">
                {% for cate in cate_list %}
                    <p><a href="/{{ username }}/category/{{ cate.0 }}">{{ cate.0 }}({{ cate.1 }})</a></p>
                {% endfor %}
            </div>
        </div>
    
        <div class="panel panel-success">
            <div class="panel-heading">随笔归档</div>
            <div class="panel-body">
                {% for date in date_list %}
                    <p><a href="/{{ username }}/archive/{{ date.0 }}">{{ date.0 }}({{ date.1 }})</a></p>
                {% endfor %}
            </div>
        </div>
     </div>
    
    4 使用标签
         {% load my_tags %}
         {% get_classification_style username %}
    
    解释:这个自定义的标签get_classification_style一旦在模板中被调用,
    首先会执行get_classification_style函数内的逻辑然后将返回的数据传送给模板classification.html去渲染,
    渲染完的结果就是这次get_classification_style标签调用的返回值。
    inclution_tag
    2 日期处理 (model中使用select)
    dashboard.py
    def issues_chart(request, project_id):
        """ 在概览页面生成highcharts所需的数据 """
        today = datetime.datetime.now().date() #datetime.date(2021, 3, 10)
        date_dict = collections.OrderedDict()
        for i in range(0, 30):
            date = today - datetime.timedelta(days=i)
            date_dict[date.strftime("%Y-%m-%d")] = [time.mktime(date.timetuple()) * 1000, 0] # 时间戳*1000
    
        # select xxxx,1 as ctime from xxxx
        # select id,name,email from table;
        # select id,name, strftime("%Y-%m-%d",create_datetime) as ctime from table;
        # "DATE_FORMAT(web_transaction.create_datetime,'%%Y-%%m-%%d')"
        result = models.Issues.objects.filter(project_id=project_id,
                                              create_datetime__gte=today - datetime.timedelta(days=30)).extra(
            select={'ctime': "strftime('%%Y-%%m-%%d',web_issues.create_datetime)"}).values('ctime').annotate(ct=Count('id'))
        # print(result) ----><QuerySet [{'ctime': '2021-03-08', 'ct': 9}]>
        for item in result:
            date_dict[item['ctime']][1] = item['ct']
    
        return JsonResponse({'status': True, 'data': list(date_dict.values())})
    model(select) 日期处理
    ---查询:
    
    日期归档查询
    
       1    date_format
    
            ============date,time,datetime===========
    
            create table t_mul_new(d date,t time,dt datetime);
    
            insert into t_mul_new values(now(),now(),now());
    
            select * from t_mul;
    
    
            mysql> select * from t_mul;
            +------------+----------+---------------------+
            | d          | t        | dt                  |
            +------------+----------+---------------------+
            | 2017-08-01 | 19:42:22 | 2017-08-01 19:42:22 |
            +------------+----------+---------------------+
            1 row in set (0.00 sec)
    
    
            select date_format(dt,"%Y/%m/%d") from t_mul;
    
    
       2  extra (在orm中使用sql语句)
    
            extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
    
            有些情况下,Django的查询语法难以简单的表达复杂的 WHERE 子句,对于这种情况, Django 提供了 extra() QuerySet修改机制 — 它能在 QuerySet生成的SQL从句中注入新子句
    
            extra可以指定一个或多个 参数,例如 select, where or tables. 这些参数都不是必须的,但是你至少要使用一个!要注意这些额外的方式对不同的数据库引擎可能存在移植性问题.(因为你在显式的书写SQL语句),除非万不得已,尽量避免这样做
    
            参数之select
    
            The select 参数可以让你在 SELECT 从句中添加其他字段信息,它应该是一个字典,存放着属性名到 SQL 从句的映射。
    
            queryResult=models.Article
                       .objects.extra(select={'is_recent': "create_time > '2017-09-05'"})
            结果集中每个 Entry 对象都有一个额外的属性is_recent, 它是一个布尔值,表示 Article对象的create_time 是否晚于2017-09-05.
    
            练习:
    
            in sqlite:
    
                article_obj=models.Article.objects
                          .extra(select={"standard_time":"strftime('%%Y-%%m-%%d',create_time)"})
                          .values("standard_time","nid","title")
                print(article_obj)
                # <QuerySet [{'title': 'MongoDb 入门教程', 'standard_time': '2017-09-03', 'nid': 1}]>
    
    
       3 日期归档查询的方式2
    
           from django.db.models.functions import TruncMonth
    
           Sales.objects
                .annotate(month=TruncMonth('timestamp'))  # Truncate to month and add to select list
                .values('month')                          # Group By month
                .annotate(c=Count('id'))                  # Select the count of the grouping
                .values('month', 'c')                     # (might be redundant, haven't tested) select month and count
    orm-日期.txt

    相关配置(版本,数据库,静态文件等)

    mysql & django
    
    1settings配置
    
    若想将模型转为mysql数据库中的表,需要在settings中配置:
    
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME':'bms',           # 要连接的数据库,连接前需要创建好
            'USER':'root',        # 连接数据库的用户名
            'PASSWORD':'',        # 连接数据库的密码
            'HOST':'127.0.0.1',       # 连接主机,默认本级
            'PORT':3306            #  端口 默认3306
        }
    }
    
    2 项目名文件下的init,写入
    import pymysql
    pymysql.install_as_MySQLdb()
    
    3两条数据库迁移命令即可在指定的数据库中创建表 :
    python manage.py makemigrations
    python manage.py migrate
    
    注意3:如果报错如下:
    django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.3 or newer is required; you have 0.7.11.None
    解决:
    MySQLclient目前只支持到python3.4,因此如果使用的更高版本的python,需要修改如下:
    通过查找路径C:ProgramsPythonPython36-32Libsite-packagesDjango-2.0-py3.6.eggdjangodbackendsmysql 这个路径里的文件把
    f version < (1, 3, 3):
         raise ImproperlyConfigured("mysqlclient 1.3.3 or newer is required; you have %s" % Database.__version__)
    注释掉 就OK了。
        
    注意4: 如果想打印orm转换过程中的sql,需要在settings中进行如下配置:
    LOGGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'handlers': {
            'console':{
                'level':'DEBUG',
                'class':'logging.StreamHandler',
            },
        },
        'loggers': {
            'django.db.backends': {
                'handlers': ['console'],
                'propagate': True,
                'level':'DEBUG',
            },
        }
    }
    1 django&mysql配置
    django1 与django 3之间的修改
    
    1 on_delete=models.CASCADE  # 表结构
    2 url(r'^', include('web.urls')), # 路由分发
    3 url(r'^rbac/', include(('rbac.urls','rbac'))) # 名称空间。传递一个元组
    4 setting:
        TEMPLATES=[
    
        'libraries': {  # Adding this section should work around the issue.
            'staticfiles': 'django.templatetags.static',
        },
    
        ]
    
    5 form组件 错误信息显示语言
        # LANGUAGE_CODE = 'en-us'
        LANGUAGE_CODE = 'zh-hans'
    
    6
    原语句if field.rel.limit_choices_to:
    修改后:将rel修改为 remote_field
    
    if field.remote_field.limit_choices_to:
    
    ##7反向解析示例:
    
    record_url = reverse('stark:web_consultrecord_list', kwargs={'customer_id': obj.pk})
    2 django-crm版本配置
    静态文件配置
    
         /static/    :  js,css,img
         /media/      :   用户上传文件
    
    访问方式:127.0.0.1:8000/static/app01/xxx.jpg
    1 在项目目录下新建一个python包 /static
     需要的话:指定应用目录,例如:/static/app01
     将静态文件放置到此目录下
    
    
    2setting配置:
    
    STATIC_URL = '/static/'
    
    STATICFILES_DIRS =[
        BASE_DIR/'static'
        ]
    3 static静态文件配置
     Media 配置
        /static/    :  js,css,img
         /media/      :   用户上传文件
    
    一旦配置了
            MEDIA_ROOT=os.path.join(BASE_DIR,"media")
    Dajngo实现:
           会将文件对象下载到MEDIA_ROOT中avatars文件夹中(如果没有avatar文件夹,Django会自动创建),user_obj的avatar存的是文件的相对路径。
    
    表模型字段:
          avatar = models.FileField(verbose_name='头像图片文件',upload_to='avatars/', default="/avatars/default.png")
    
    settings.py
         MEDIA_URL="/media/"
         import os 
         MEDIA_ROOT = os.path.join(BASE_DIR, "media")
         
    urls.py:
    from django.views.static import serve
    from cnblog import  settings
     # media配置:
    re_path(r"media/(?P<path>.*)$",serve,{"document_root":settings.MEDIA_ROOT})
    4 media静态文件配置
    基于admin组件录入数据
    
    前期准备:
     创建超级用户:python manage.py createsuperuser
     访问:127.0.0.1/admin
    
    示例一:
    以项目下的course APP为例:
    1 模型层处理  (course/model.py)
    from django.db import models
    # Create your models here.
    
    from django.db import models
    
    # 将表名写入__all__
    __all__ = ["Category", "Course", "CourseDetail", "Teacher", "DegreeCourse", "CourseChapter",
               "CourseSection", "PricePolicy", "OftenAskedQuestion", "Comment", "Account", "CourseOutline"]
    2 admin下注册 ( course/admin.py)
    from django.contrib import admin
    
    # Register your models here.
    from . import models
    
    for table in models.__all__:
        admin.site.register(getattr(models, table))
    
    
    示例二:
    
    在blog/admin.py文件:
    
    from django.contrib import admin
    
    # Register your models here.
    from blog import models
    
    admin.site.register(models.UserInfo)
    admin.site.register(models.Blog)
    admin.site.register(models.Category)
    admin.site.register(models.Tag)
    admin.site.register(models.Article)
    admin.site.register(models.ArticleUpDown)
    admin.site.register(models.Article2Tag)
    admin.site.register(models.Comment)
    5 admin录入数据
    1.django时区
    
    # datetime.datetime.now() / datetime.datetime.utcnow() => utc时间
    # TIME_ZONE = 'UTC'
    
    # datetime.datetime.now() - 东八区时间 / datetime.datetime.utcnow() => utc时间
    TIME_ZONE = 'Asia/Shanghai'
    
    # 影响自动生成数据库时间字段;
    #       USE_TZ = True,创建UTC时间写入到数据库。
    #       USE_TZ = False,根据TIME_ZONE设置的时区进行创建时间并写入数据库
    USE_TZ = False
    6 django时区问题
    5 编辑器文件上传功能(views/wiki.py)
    from django.views.decorators.csrf import csrf_exempt
    from django.views.decorators.clickjacking import xframe_options_sameorigin
    
    @csrf_exempt
    @xframe_options_sameorigin
    def wiki_upload(request, project_id):
        """ markdown插件上传图片 """
        pass
    markdown等编辑器文件上传问题

    相关项目 --Django markdown文档

    点击下载项目

    链接:https://pan.baidu.com/s/1reDH1z7e_4VRoQd1sEi7Lg
    提取码:huaw

    点击下载相关markdown文档 

    链接:https://pan.baidu.com/s/1wFcrINQje66H67qxvPJERQ

     

    作者:华王 博客:https://www.cnblogs.com/huahuawang/
  • 相关阅读:
    继承
    rpm使用
    weblogic报outOfMemory
    linux能访问外网但ping不通百度
    zookeeper启动异常问题
    Oracle查看表的变动信息
    Linux创建、删除软链接
    zookeeper开机自启
    linux中oracle自启动
    Weblogic命令模式安装
  • 原文地址:https://www.cnblogs.com/huahuawang/p/14806644.html
Copyright © 2020-2023  润新知