第十一篇 Django 【进阶篇】
分类:
IT文章
•
2022-06-15 17:57:55
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