第十一篇 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']
#!/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()
#!/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()
-插入多条数据
#!\Users\Local\Programs\Python37 # -*- 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)+"\n") 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
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标签调用的返回值。
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 ```
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 单表查询--多表查询
<1> all(): 查询所有结果 <2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象 <3> get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个, 如果符合筛选条件的对象超过一个或者没有都会抛出错误。 <4> exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象 <5> order_by(*field): 对查询结果排序 <6> reverse(): 对查询结果反向排序 <8> count(): 返回数据库中匹配查询(QuerySet)的对象数量。 <9> first(): 返回第一条记录 <10> last(): 返回最后一条记录 <11> exists(): 如果QuerySet包含数据,就返回True,否则返回False <12> values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 model的实例化对象,而是一个可迭代的字典序列 <13> values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列 <14> distinct(): 从返回结果中剔除重复纪录
Book.objects.filter(price__in=[100,200,300]) Book.objects.filter(price__gt=100) Book.objects.filter(price__lt=100) Book.objects.filter(price__range=[100,200]) Book.objects.filter(title__contains="python") Book.objects.filter(title__icontains="python") Book.objects.filter(title__startswith="py") Book.objects.filter(pub_date__year=2012)
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
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/")
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")
用户认证组件: 功能:用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())
<!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>
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
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
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())
<!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>
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)
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 解决跨域问题
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))
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')
基于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)
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标签调用的返回值。
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())})
---查询: 日期归档查询 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
相关配置(版本,数据库,静态文件等)
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:\Programs\Python\Python36-32\Lib\site-packages\Django-2.0-py3.6.egg\django\db\backends\mysql 这个路径里的文件把 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', }, } }
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})
静态文件配置 /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' ]
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})
基于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)
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
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
# settings.py CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379/0", "TIMEOUT": None, "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", "CONNECTION_POOL_KWARGS": {"max_connections":100}, "DECODE_RESPONSES": True, # 自动将byte转成字符串 "PASSWORD": "", # 设置密码 } } } from django.core.cache import cache #引入缓存模块 cache.set('v', '555', 60*60) #写入key为v,值为555的缓存,有效期60分钟 cache.has_key('v') #判断key为v是否存在 v =cache.get('v') #获取key为v的缓存
相关项目 --Django markdown文档
链接:https://pan.baidu.com/s/1reDH1z7e_4VRoQd1sEi7Lg
提取码:huaw
链接:https://pan.baidu.com/s/1wFcrINQje66H67qxvPJERQ
作者:华王
博客:https://www.cnblogs.com/huahuawang/