用户功能
管理功能
django支持任意多个appcss
注意:html
1. 使用命令行建立项目,不会自动建立templates文件夹,只能手动建 2. settings文件中手动写[os.path.join(BASE_DIR, 'templates')]
pycharm建立:前端
可以自动建立template文件夹和路径配置python
也可以支持建立一个应用并注册。mysql
from django.shortcuts import render,HttpResponse, redirect
HttpResponsenginx
# 返回字符串 urls: urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'login/', views.login), def login(request): return HttpResponse('Hello word~')
rendergit
# 返回HTML页面,而且能够为该html传值 urls: urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'login/', views.login), url(r'reg/', views.reg), ] def reg(request): user_dict = {'name':'jason','pwd':123} # return render(request,'reg.html') # 给模板传值的方式1 # return render(request, 'reg.html',{'xxx':user_dict}) # 将user_dict传递给reg.html页面 页面上经过xxx就可以获取到该字典 # 给模板传值的方式2 return render(request,'reg.html',locals()) # 会将当前名称空间中全部的变量名所有传递给reg.html页面 # locals() 会出现效率问题,但仍是要是用
redirect程序员
# 重定向 既能够是咱们本身的路径也能够是网上的路径 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'login/', views.login), url(r'reg/', views.reg), url(r'home/', views.home), url(r'index/', views.index), ] def home(request): # return redirect('/index') return redirect('http://www.xiaohuar.com') def index(request): return HttpResponse('index') 注意: 重定向的能够是本身写的,也能够是第三方的。
django返回的都是HttpResponse对象正则表达式
咱们写的视图函数必须得有返回值sql
用户可以访问到的全部资源,都是程序员提早爆露好的,若是没有暴露,用户永远也访问不到。
用户可以在浏览器中输入网址访问到相应的资源,前提是后端暴露了该资源接口。
在django中若是你想让用户访问到对应的资源,咱们只须要在urls.py中设置对应关系,反过来若是我没有在urls.py中开设资源 用户就永远就访问不到对应的资源。
返回给浏览器的html页面上全部的静态资源 也须要请求后端加载获取
一般咱们将网站所用到的html文件所有存放在templates文件夹下
网站用到的静态资源所有存放到static文件夹下
网站所用到的
本身写好的js
本身写好的CSS
第三方的框架 bootstrap fontwesome sweetalert
一般状况下网站所用到的静态文件资源,统一都放在static文件夹下
settings: STATIC_URL = '/static/' # 是访问静态资源的接口前缀 """只要你想访问静态资源 你就必须以static开头""" # 手动配置静态文件访问资源 STATICFILES_DIRS = [ os.path.join(BASE_DIR,'static'), os.path.join(BASE_DIR,'static1'), # os.path.join(BASE_DIR,'static2'), ] # (支持多个)
打开网页,F12, 自定义关闭旁边,Network, Disable cache (while DevTools is open),关闭缓存
接口前缀 动态解析 {% load static %} <link rel="stylesheet" href="{% static'bootstrap/css/bootstrap.min.css' %}"> <script src="{% static 'bootstrap/js/bootstrap.min.js' %}"></script>
form是一个复杂的系统标签,其内部又可包含不少的一些输入标签
例如input 输入文本标签 checkbox 多选标签等等
form表单有几个属性咱们须要注意一下
1:action属性,里面写的是url连接,接就是表单提交的地址
2:method属性,里面写的是数据提交的方式,能够写入get或者post
3:enctype属性,提交数据的编码格式
from表单上传文件
form表单上传文件 1.提交方式必须是post 2.须要将form标签的enctype属性由默认的urlencoded改成formdata 后端须要从request.FILES中获取上传的文件 django内部针对不一样数据格式的数据 会解析到不一样的方法中 request.GET request.POST request.FILES
form表单被咱们应用在先后台交互的环节的,里面的值能够在后台经过某些key取出来
下面就来说解不一样标签取值的方法
1. input 标签
input标签咱们最为常见,里面有三个属性比较重要
a. type 他是表明input的类型
b. name 他就是后台取值的依据(key)
c. val 他是咱们输入的值,也是后台须要的值
而后咱们根据type的类型,又能够把input进行细分
a. text 表示普通的文本,明文输入
b. password 输入的也是文本,密文输入
c. number 输入的是数字,不是数字不让输入
d. submit 提交按钮,提交form表单的内容
e. button 普通的按钮
f. radio 单选框,咱们须要注意的是单选框的全部的name值必须相同
若是name不相同,就说明不在同一个选择方位,也就不存在单选,而后想要在后台取到他的值,
你必须在定义的时候给附上一个值给value,这样才能取到值
g. checkbox 复选框,内容和单选框同样
h. file 选择文件,能够选择文件提交给后台
以上基本是input的全部类型,须要注意几个点
1.取值都是经过name进行取值,因此必须给name赋值
2.文本类型想要附上初始值,直接在value中加入值就能够
3.选择框若是想要默认选中谁,那就在谁的标签中加入checked属性
2. select 标签
select标签是一个下拉框的形式让用户进行选择选项
因此select标签中必须包含option标签才能显示属性
形式为:
而后select中有全局属性name,这个name是后台又来进行取值的
每一个option标签的文本内容是显示给用户看的,咱们须要取的是option标签中的value属性,因此在开始必须给option的value赋值
后台经过select的name取值,直接取到的就是对应option的value
若是咱们向让他默认选择某个option,能够在option标签中加入selected属性,若是都不加,默认是显示第一个
3. button 按钮标签
新出的标签,与input中type为button的按钮同样
4. textarea 文本框标签
与input中的text同样都是输入文本的,可是textarea标签没有字数的限制,而且输入框能够拖拉。
from表单默认朝后端提交的方式 默认是get请求
get请求携带参数的方式,是在url后面?
url ?username=admin&password=123
缺点:
若是前期要提交post请求 就去settings中注释掉一个中间件
如何获取请求方式
获取post请求携带的数据
request.POST
获取get请求携带的数据:request.GET
get和post在后端获取用户数据的时候 规律是同样的
<QueryDict: {'username': ['admin', 'tank'], 'password': ['123']}>
tank <class 'str'>
123 <class 'str'>
request.POST.get('username') 默认只取列列表的最后一个元素
若是你想将列表完整的取出 你必须用getlist()
request.GET # 你就把它当成一个大字典 里面放的是get请求携带过来的数据 request.POST # 你就把它当成一个大字典 里面放的是post请求携带过来的数据 """上面的大字典 全部的value都是一个列表""" request.GET.get('key') # 默认取的是列表的最后一个元素 并非直接将列表取出 request.GET.getlist('key') # 直接将value的列表取出 request.POST.get('key') # 默认取的是列表的最后一个元素 并非直接将列表取出 request.POST.getlist('key') # 直接将value的列表取出
点击database,添加数据库
Django自带一个小型的sqlite3数据库....该数据库功能不是很强大 尤为是对日期格式的数据 不是很兼容
Django链接MySQL
1. 配置文件
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', # 指定数据库 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), # 究竟是用哪一个库 'USER':'root', 'PASSWORD':'root', 'HOST':'127.0.0.1', 'PORT':3306, 'CHARSET':'utf8' } }
如今已经再也不使用MySQLdb模块,可是默认仍是使用MySQLdb 链接数据库,因此告诉Django不要使用MySQLdb,而是改用pymysql 链接
在项目名称下边的__init__.py也能够在应用名下面的__init__.py文件中指定
import pymysql
pymysql.install_as_MySQLdb()
orm对象关系映射
类 数据库的表
对象 表的记录
对象获取属性 记录的某个字段对应的值
优势: 可以让一个不会数据库操做的人也可以简单快捷的去使用数据库
缺点: 因为封装程度过高,可能会致使sql语句的执行效率变低
有时候结合项目需求可能须要你手写sql语句
注意事项:
1. django的orm不会自动帮你建立库,须要你手动指定一个django项目用一个数据库 2. 表会自动帮你建立,你只须要书写符合Django orm语法的代码便可
from django.db import models # Create your models here. class Userinfo(models.Model): # 设置id字段为userinfo表的主键 id int primary key auto_increment id = models.AutoField(primary_key=True) # 在django中 你能够不指定主键字段 django orm会自动给你当前表新建一个名为id的主键字段 # 设置username字段 username varchar(64) CharField必需要指i定max_length参数 username = models.CharField(max_length=32) # 在django orm中 没有char字段 可是django 暴露给用户 能够自定义char字段 # 设置password字段 password int password = models.IntegerField()
数据库迁移(同步)命令:
python manage.py makemigrations # 不会建立表 仅仅是生成一个记录 将你当前的操做记录到一个小本本上(migrations文件夹)
python manage.py migrate # 将你的orm语句真正的迁移到(同步)到数据库中
只要你在models.py中修改了跟数据库相关的代码 你就必须从新开始执行上面两条命令
当你第一次执行上面两条命令的时候 django会自动建立不少张表 这些表都是django默认须要用到的表
你本身写的模型类所对应的表 表名有固定格式
应用名_表名
在项目的modles文件夹下 phone = models.BigIntegerField(default=110) # 新增的字段 能够提早设置默认值 addr = models.CharField(max_length=64,null=True) # 新增的字段 能够设置为空
新增的字段
1.直接提供默认值 default
2.设置改字段能够为空 null=True
注意的是 不要轻易的注释models.py中任何跟数据库相关的代码
主要是跟数据库相关的代码 你在处理的时候必定要当心谨慎
能够再客户端浏览器显示
{# 模板语法注释 #},不能在网页显示,只能在后端显示,
get()
1. 条件存在的状况下,获取的直接是数据对象的自己
2. 条件不存在的状况下,会直接报错,因此不推荐使用get方法查询数据
##### 1. create()
1. 括号内写关键字参数的形式,建立数据 2. 该方法会有一个返回值,返回值就是当前的对象前身。 ##### 2. 利用对象点方法的方式 user_obj = User(username='jason') user_obj.save() # 将当前对象保存到数据库中
def edit_user(request): # 1.如何获取用户想要编辑的数据 edit_id = request.GET.get('edit_id') if request.method == 'POST': # 将用户新修改的全部的数据 username = request.POST.get("username") password = request.POST.get("password") """POST中也是能够获取GET请求携带的参数""" # 去数据库中修改对应的数据 # 方式1: models.Userinfo.objects.filter(pk=edit_id).update(username=username,password=password)# 批量更新 # 方式2: 获取当前数据对象 而后利用对象点属性的方式 先修改数据 而后调用对象方法保存 # 不推荐你使用第二种方式 效率低 挨个从新写入一遍 edit_obj = models.Userinfo.objects.filter(pk=edit_id).first() # pk可以自动帮你查询出当前表的主键字段名 edit_obj.username = username edit_obj.password = password edit_obj.save() """update方法会将filter查询出来的queryset对象中全部的数据对象所有更新""" # 跳转到数据展现页面 return redirect('/userlist') # 2.根据主键值去数据库中查询出当前对象 展现给用户看 edit_obj = models.Userinfo.objects.filter(pk=edit_id).first() # pk可以自动帮你查询出当前表的主键字段名 # 3.将查询出来的数据对象传递给前端页面 展现给用户看 return render(request,'edit_user.html',locals())
def delete_user(request): # 获取想要删除的数据id 直接删除 delete_id = request.GET.get('delete_id') models.Userinfo.objects.filter(pk=delete_id).delete() # 批量删除 return redirect('/userlist')
图书管理系统OR表建立:
表与表之间的关系:
一对多:外键字段创建在多的一
models.Foreignkey(to="关联的表名") # 自动建表关系,默认就是跟关联表的主键字段
“”“
Foreignkey字段在建立的时候 orm会自动在字段后面加_id
"""
多对多: ManyToManyField(to=“关联的表名”) # 并不会建立一个实际字段,仅仅是用来告诉django orm自动建立第三张表
一对一:
OneToOneField(to="关联的表名")
"""
OneToOneField字段在建立的时候orm会自动在字段后面加_id
"""
一对一(做者和做者信息)
一对多(书和出版社)
多对多(书和做者)
图书表(book):id/title/price/publish_id
出版社表(publish):id/name/ addr
做者表(author): id/name/phone
多对多第三方表:id/book_id/author_id
urls.py: 路由与视图函数的对应关系》》》路由层
无名分组 urlpatterns = [ url(r'^test/(\d+)/', views.test) ] 会将括号内的内容当作位置参数传递给后面的视图函数test(reqiest, args) 在调用视图函数test的时候 会将\d+匹配到的内容 当作位置参数传递给test 有名分组(给正则表达式定义别名) urlpatterns = [ url(r'^test/(?P<month>\d+)/', views.test) ] 定义了别名month 会将括号内的内容当作关键字传递给后面的视图函数test(request, month=123) 在调用视图函数test的时候 会将\d+匹配到的内容 当作关键字参数(month='')传递给test views内定义的形参必须是month 无名和无名不能结合使用,可是能够单独使用. 有名无名单独使用的状况下 能够用多个
注意:+表示(1-无穷大)*(0-无穷大)?(0-1)
根据某一个东西动态解析出一个结果,该结果能够直接访问对应的url。
给路由与视图函数对应关系 起一个别名 后续根据这个别名 就可以动态解析出所对应的url。
url(r'^test_add/', views.testadd,name='xxx')
起别名 别名必定不要重复
前端解析
{% url 'xxx' %}
后端解析
from django.shortcuts import render,HttpResponse,redirect,reverse
url = reverse('修更名')
<a href="{% url 'xxx' year=1 %}">222</a> <a href="{% url 'xxx' 1 %}">222</a>
url = reverse('xxx', args=(1,)) url = reverse('xxx', kwargs=('year':231,))
经过名字可以动态表达出一个结果,这个结果可以访问到这个名字对应的url
url(r'^edit_user/(\d+)/',views.edit_user,name='edit') user_queryset = models.User.objects.all() {% for user_obj in user_queryset %} <td> <a href="{% url 'edit' user_obj.pk %}">编辑</a> <a>删除</a> </td>{% endfor %}def edit(request,edit_id): pass
注意: 反向解析的别名必定不能重复
Django里面的APP能够有本身的static文件,templates文件夹,urls.py等。正是因为上述的特色 你基于django开发项目 就真正能够作到分组分功能分模块独立的去开发。
注意:当应用特别多的时候 总路由中的代码过于冗长 很差维护
项目名下的urls.py再也不作路由与视图函数对应关系了,而是作一个中转站,只负责将请求分发到不一样的app中
在APP的urls.py 完成路因为视图函数的对应关系
from django.conf.urls import url,include url(r'^app01/',include(app01_urls)), url(r'^app02/',include(app02_urls)) # 1.在应用下本身手动建立urls.py # 2.在路由中导入 # 1 from app01 import urls as app01_urls from app02 import urls as app02_urls url(r'^app01/',include(app01_urls)), url(r'^app02/',include(app02_urls)) # 2 url(r'^app01/',include('app01.urls')), url(r'^app02/',include('app02.urls'))
总路由
url(r'^app01/',include('app01.urls',namespace='app01'))
url(r'^app02/',include('app02.urls',namespace='app02'))
print(reverse('app01:index')) print(reverse('app02:index'))
由于起别名冲突才用到名称空间,因此一般状况下 起别名的时候 前面能够加上你的应用名
url看起来像是一个静态页面(.html结尾)
将动态网页伪装成静态的
这样作能够提升搜索引擎的SEO查询优先级
搜索在收录网站的时候会优先收录看上去像是静态文件的资源
可是不管你怎么使用伪静态进行优化 你也干不过RMB玩家(参考百度)
不一样的项目应该有各自独立的解释器环境 最大化节省资源
实际功能中针对不一样的项目 会有一个叫requestsments.txt文件
该文件中列出来是一个个该项目须要用的到模块名和版本号
eg:
django = 1.11.11
nginx = 1.21
后期经过命令直接会去下载该文件内全部的模块及对应版本
每建立一个虚拟环境,就相似于从新下载一个纯净的python解释器环境
虚拟环境会占用硬盘资源,因此不要建立太多。
#### Django1.x #### Django2.x
区别:
urls.py中1.x用的是url,而2.x用的是path
而且2.x中的path第一个不支持正则表达式,写什么就匹配什么
若是你以为很差用,2.x里面还有re_path 这个re_path就是你1.x里面的url
HttpResponse # 返回字符串
render # 返回一个html页面 还能够给模板传递
from django.template import Template,Context def index(request): res = Template("<h1> {{ user }} </h1>") con = Context({'user':{'username':'jason','pwd':'123'}}) ret = res.render(con) print(ret) return HttpResponse(ret)
redirect # 重定向
JsonResponse
返回json格式数据
为何要给前端回json 格式字符串
先后端分离 就是基于json格式传输数据的
后端给前端返回一个json的格式的字符串(至关于反悔了一个大字典)
而后前端利用序列化反序列化转换成前端对应的数据类型
js经常使用数据类型:
数值类型
字符类型
数组
自定义对象
undefined与null
布尔值
symbol
JSON.stringify 序列化 >>> json.dumps
JSON.parse 反序列 >>> json.loads
FBV (Function Based View) 基于函数的视图
CBV (Class Based View) 基于类的视图
CBV 的请求流程
当服务端使用cbv模式的时候,用户发给服务端的请求包含urI和method,这两个信息都是字符串类型
服务端经过路由映射表匹配成功后会自动去找dispatch方法,而后Django会经过dispatch反射的方式找到类中对应的方法并执行
类中的方法执行完毕以后,会把客户端想要的数据返回给dispatch方法,由dispatch方法把数据返回经客户端
在类中写的两个方法(get和post)
get请求会触发get方法,post请求会触发post方法
url(r'^reg/',views.MyReg.as_view()), # url(r'^reg/',views.view) # CBV和FBV在路由匹配上 规则都是同样的 都是路由后面跟的函数的内存地址
CBV结合源码
# CBV路由 url(r'^reg/',views.MyReg.as_view())(经过as_view进入源码) @classonlymethod def as_view(cls, **initkwargs): def view(request, *args, **kwargs): self = cls(**initkwargs) # cls就是咱们本身的写的MyReg类 if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get self.request = request self.args = args self.kwargs = kwargs # 上面的一通操做 就是给咱们本身写的类的对象赋值 return self.dispatch(request, *args, **kwargs) # 对象在查找属性或方法的时候 顺序是什么? 先从本身找 再从产生对象的类中找 再去类的父类中找... """也就意味着你在看源码的时候 你必定要牢记上面的话""" return view # views.py from django.views import View class MyReg(View): def get(self,request): return render(request,'reg.html') def post(self,request): return HttpResponse("我是MyReg类中post方法") """CBV最精髓的部分""" def dispatch(self, request, *args, **kwargs): if request.method.lower() in self.http_method_names: # 判断当前请求方式在不在默认的八个请求方式中 handler = getattr(self, request.method.lower(), self.http_method_not_allowed) # handler = getattr(本身写的类产生的对象,'小写的请求方法(get\post)','获取不到对应的方法就报错') # handler就是咱们本身定义的跟请求方法相对应的方法的函数内存地址 else: handler = self.http_method_not_allowed return handler(request, *args, **kwargs) # 在调用获取到的方法
CBV说明1:
在url中会执行一个叫作as_view的方法,这个方法在加载url时候会执行 获得一个返回值view 是一个函数 供url调用,
当url执行view时候,会把下边这句代码做为返回值
self.dispatch(request, *args, **kwargs)
所view 会调用当前调用类的dispatch
CBV说明2:
在执行dispatch的时候,若是views中的视图类 自定义了dispatch那么将优先执行自定义的dispatch 由此可在请求处理前增长一些处理,
而后再用super方法去调用父类的dispatch ,固然也能够本身把父类的功能所有写在本身的自定义里边。
简单的说-----分发
复杂的说-----找到此次请求对应的类型,而后用反射把这个方法取到,而后做为本身的返回值,返回给调用这个方法的view
方式二:
案例:
urls.py
from django.urls import path,register_converter,re_path from app01 import views urlpatterns = [ re_path(r'^login/',views.LoginView.as_view()), # 必须调用类下的方法as_view ]
views.py
from django.shortcuts import render,HttpResponse,redirect from django.views import View class LoginView(View): def dispatch(self, request, *args, **kwargs): # 可在该方法内作一些预处理操做 # 当请求url为:http://127.0.0.1:8008/login/会先触发dispatch的执行 # 若是http协议的请求方法为GET,则调用下述get方法 # 若是http协议的请求方法为POST,则调用下述post方法 obj=super().dispatch(request, *args, **kwargs) # 必须继承 父类的dispatch功能 return obj # 必须返回obj def get(self,request): return render(request,'login.html') def post(self,request): name=request.POST.get('name') pwd=request.POST.get('pwd') if name == 'egon' and pwd == '123': res='登陆成功' else: res='用户名或密码错误' return HttpResponse(res)
测试:
python manage.py runserver 8001 # 验证GET请求:在浏览器输入:http://127.0.0.1:8001/login/ # 验证POST请求:在表单内输入数据而后提交
django的配置文件有两个 一个是暴露给用户能够自定义配置的 一个是默认的全局配置文件 用户指定了就用用户的 用户没有指定就用默认的 from django.conf import settings settings = LazySettings() class LazySettings(LazyObject): def _setup(self, name=None): # os.environ你能够把它当作是一个全局的大字典 settings_module = os.environ.get(ENVIRONMENT_VARIABLE) # 从大字典中取值 # settings_module = 'day59.settings' self._wrapped = Settings(settings_module) # Settings('day59.settings') class Settings(object): def __init__(self, settings_module): # settings_module = 'day59.settings' for setting in dir(global_settings): # 循环获取global_settings文件中全部的名字 if setting.isupper(): # 在判断名字是不是大写 # 若是是大写 利用反射 获取到大写的名字所对应的值 不停地添加到对象中 setattr(self, setting, getattr(global_settings, setting)) # store the settings module in case someone later cares self.SETTINGS_MODULE = settings_module mod = importlib.import_module(self.SETTINGS_MODULE) # 'day59.settings' # from day59 import settings # mod 指代的就是暴露给用户的配置文件模块名 for setting in dir(mod): # 循环获取暴露给用户配置文件中全部的名字 if setting.isupper(): # 判断是不是大写 setting_value = getattr(mod, setting) # 若是是大写 获取大写的变量名所对应的值 setattr(self, setting, setting_value) # 不停的给对象设置值 思考:基于django settings源码 实现本身的项目也有两个配置文件 一个是暴露给用户的一个是项目默认 用户配置了 就用用户的 用户没有配置 就用默认的
django settings源码 django暴露给用户一个自定义配置的文件 用户配置了就用用户的 用户没有配置就使用默认的 而且配置文件中的变量名必须是大写才有效 from django.conf import settings settings = LazySettings() class LazySettings(object): ... class Settings(object): # 循环获取默认的配置文件中全部的大写配置 # 利用setattr给对象不停的设置键值对 # 再循环获取暴露给用户的自定义配置文件中全部的大写的配置 # 再利用setattr给对象不停的设置键值对 """字典的键存在的状况 再设值其实就是替换"""
为将前端页面和Python的代码分离, Django专门提供了模板系统 (Template System,即模板层)来实现 django的模板=HTML代码+模板语法 .
存放于templates目录下的html文件称之为模板文件,若是咱们想要返回的html页 面中的数据是动态的,那么必须在html页面中嵌入变量,这便用到了django的模 板语法。
{{}}变量相关
{%%}逻辑相关
传函数名的时候 会自动加括号调用函数 将函数的返回值展现在html页面上
django模板语法不支持函数传参
django模板语法在获取容器类型内部元素的值的时候 统一只采用 句点符(.)
#### 1. 变量:{{ 变量名 }}
若是html代码中的数据不是固定死的,而是动态变化的,则必须在html中嵌入变 量,为此,模板语法提供了变量的概念,容许咱们在html代码中嵌入变量,咱们 只须要在视图函数中用render方法为html文件中指定的变量赋值便可
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>{{ msg }}</p> <p>{{ dic }}</p> <p>{{ obj }}</p> <p>{{ li }}</p> </body> </html>
咱们须要在视图函数中为模板test.html的变量名msg、li、dic、obj、obj_li赋值,views.py内容以下
from django.shortcuts import render def test(request): # 传给模板的变量值能够是任意python类型,以下 msg='hello world' dic={'k1':1,'k2':2} class Person(object): def __init__(self,name,age): self.name=name self.age=age obj=Person('egon',18) li = [1,'aaa',obj] return render(request,'test.html',{'msg':msg,'dic':dic,'obj':obj,'li':li}) # 注意: # 一、render函数的第三个参数包含了要传给模板的变量值,是一个字典类型,该字典中的key必须与模板文件中 的变量名相对应,render函数会去templates目录下找到模板文件,而后根据字典中的key对应到模板文件中的变量名 进行赋值操做,最后将赋值后的模板文件内容返回给浏览器 # 二、能够将render函数的第三个参数简写为locals(),以下 return render(request,'test.html',locals()) #locals()会将函数test内定义的名字与值转换为字 典中的k与v
当视图函数传给模板的值中包含多个元素时,若想取出其中的单个元素,就必须
使用句点符了。
句点符既能够引用容器类型的元素,也能够引用对象的方法,以下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--调用字符串对象的upper方法,注意不要加括号--> <p>{{ msg.upper }}</p> <!--取字典中k1对应的值--> <p>{{ dic.k1 }}</p> <!--取对象的name属性--> <p>{{ obj.name }}</p> <!--取列表的第2个元素,而后变成大写--> <p>{{ li.1.upper }}</p> <!--取列表的第3个元素,并取该元素的age属性--> <p>{{ li.2.age }}</p> </body> </html>
过滤器相似于python的内置函数,用来把视图传入的变量值加以修饰后再显示,
具体语法以下
{{ 变量名|过滤器名:传给过滤器的参数 }}
经常使用内置过滤器
一、default 做用:若是一个变量值是False或者为空,使用default后指定的默认值,不然,使用变量自己的值,若是 value=’‘则输出“nothing” {{ value|default:"nothing" }} 二、length 做用:返回值的长度。它对字符串、列表、字典等容器类型都起做用,若是value是 ['a', 'b', 'c', 'd'],那么输出是4 {{ value|length }} 三、filesizeformat #做用:将值的格式化为一个"人类可读的"文件尺寸(如13KB、4.1 MB、102bytes等等),若是 value 是 12312312321,输出将会是 11.5 GB {{ value|filesizeformat }} 四、date 做用:将日期按照指定的格式输出,若是value=datetime.datetime.now(),按照格式Y-m-d则输出2019-02-02 {{ value|date:"Y-m-d" }} 五、slice 做用:对输出的字符串进行切片操做,顾头不顾尾,若是value=“egon“,则输出"eg" {{ value|slice:"0:2" }} 六、truncatechars 做用:若是字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾, 若是value=”hello world egon 嘎嘎“,则输出"hello...",注意8个字符也包含末尾的3个点 {{ value|truncatechars:8 }} 七、truncatewords 做用:同truncatechars,但truncatewords是按照单词截断,注意末尾的3个点不算做单词,若是value=” hello world egon 嘎嘎“,则输出"hello world ..." {{ value|truncatewords:2 }} 八、safe(前端) 做用:出于安全考虑,Django的模板会对HTML标签、JS等语法标签进行自动转 义,例如value="<script>alert(123)</script>",模板变量 {{ value }}会被渲染成< script>alert(123)</script>交给浏览器后会被解析成普通字符”<script>alert(123)</script>“, 失去了js代码的语法意义,但若是咱们就想让模板变量{{ value }}被渲染的结果又要有语法意义,那么就用到了过滤器safe, 好比value='<a href="https://www.baidu.com">点我啊</a>', 在被safe过滤器处理后就成为了真正的超连接,不加safe过滤器则会当作普通字符显示’<a href="https://www.baidu.com">点我啊</a>‘ {{ value|safe }}
过滤器 | 描述 | 示例 |
---|---|---|
upper | 以大写方式输出 | {{ user.name|upper}} |
add | 给value加上一个数值 | {{ user.age|add:”5” }} |
addslashes | 单引号加上转义号 | |
capfirst | 第一个字母大写 | {{ ‘good’|capfirst }} 返回”Good” |
center | 输出指定长度的字符串,把变量居中 | {{ “abcd”|center:”50” }} |
cut | 删除指定字符串 | {{ “You are not a Englishman”|cut:”not” }} |
date | 格式化日期 | |
default | 若是值不存在,则使用默认值代替 | {{ value|default:”(N/A)” }} |
default_if_none | 若是值为None, 则使用默认值代替 | |
dictsort | 按某字段排序,变量必须是一个dictionary | {% for moment in moments|dictsort:”id” %} |
dictsortreversed | 按某字段倒序排序,变量必须是dictionary | |
divisibleby | 判断是否能够被数字整除 | {{ 224|divisibleby:2 }} 返回 True |
escape | 按HTML转义,好比将”<”转换为”<” | |
filesizeformat | 增长数字的可读性,转换结果为13KB,89MB,3Bytes等 | {{ 1024|filesizeformat }} 返回 1.0KB |
first | 返回列表的第1个元素,变量必须是一个列表 | |
floatformat | 转换为指定精度的小数,默认保留1位小数 | {{ 3.1415926|floatformat:3 }} 返回 3.142 四舍五入 |
get_digit | 从个位数开始截取指定位置的数字 | {{ 123456|get_digit:’1’}} |
join | 用指定分隔符链接列表 | {{ [‘abc’,’45’]|join:’’ }} 返回 abc45 |
length | 返回列表中元素的个数或字符串长度 | |
length_is | 检查列表,字符串长度是否符合指定的值 | {{ ‘hello’|length_is:’3’ }} |
linebreaks | 用 或 标签包裹变量 |
{{ “Hi\n\nDavid”|linebreaks }} 返回 Hi David |
linebreaksbr | 用标签代替换行符 | |
linenumbers | 为变量中的每一行加上行号 | |
ljust | 输出指定长度的字符串,变量左对齐 | {{‘ab’|ljust:5}}返回 ‘ab ’ |
lower | 字符串变小写 | |
make_list | 将字符串转换为列表 | |
pluralize | 根据数字肯定是否输出英文复数符号 | |
random | 返回列表的随机一项 | |
removetags | 删除字符串中指定的HTML标记 | {{value|removetags: “h1 h2”}} |
rjust | 输出指定长度的字符串,变量右对齐 | |
slice | 切片操做, 返回列表 | {{[3,9,1]|slice:’:2’}} 返回 [3,9]{{ 'asdikfjhihgie'|slice:':5' }} 返回‘asdik’ |
slugify | 在字符串中留下减号和下划线,其它符号删除,空格用减号替换 | {{ '5-2=3and5 2=3'|slugify }} 返回 5-23and5-23 |
stringformat | 字符串格式化,语法同python | |
time | 返回日期的时间部分 | |
timesince | 以“到如今为止过了多长时间”显示时间变量 | 结果可能为 45days, 3 hours |
timeuntil | 以“从如今开始到时间变量”还有多长时间显示时间变量 | |
title | 每一个单词首字母大写 | |
truncatewords | 将字符串转换为省略表达方式 | {{ 'This is a pen'|truncatewords:2 }}返回``This is ... |
truncatewords_html | 同上,但保留其中的HTML标签 | {{ '<p>This is a pen</p>'|truncatewords:2 }}返回``<p>This is ...</p> |
urlencode | 将字符串中的特殊字符转换为url兼容表达方式 | {{ ‘http://www.aaa.com/foo?a=b&b=c’|urlencode}} |
urlize | 将变量字符串中的url由纯文本变为连接 | |
wordcount | 返回变量字符串中的单词数 | |
yesno | 将布尔变量转换为字符串yes, no或maybe | |{{ True|yesno }}{{ False|yesno }}{{None|yesno }} 返回 yesno maybe |
标签是为了在模板中完成一些特殊功能,语法为{% 标签名 %},一些标签还须要搭 配结束标签 {% endtag %}
一、遍历每个元素: {% for person in person_list %} <p>{{ person.name }}</p> {% endfor %} 二、能够利用{% for obj in list reversed %}反向循环。 三、遍历一个字典: {% for key,val in dic.items %} <p>{{ key }}:{{ val }}</p> {% endfor %} 四、循环序号能够经过{{ forloop }}显示 forloop.counter 当前循环的索引值(从1开始) forloop.counter0 当前循环的索引值(从0开始) forloop.revcounter 当前循环的倒序索引值(从1开始) forloop.revcounter0 当前循环的倒序索引值(从0开始) forloop.first 当前循环是第一次循环则返回True,不然返回False forloop.last 当前循环是最后一次循环则返回True,不然返回False forloop.parentloop 本层循环的外层循环 五、for标签能够带有一个可选的{% empty %} 从句,在变量person_list为空或者没有被找到时,则执行empty子 句 {% for person in person_list %} <p>{{ person.name }}</p> {% empty %}
# 一、注意: {% if 条件 %}条件为真时if的子句才会生效,条件也能够是一个变量,if会对变量进行求值,在变量值为空、或者视图没有为其传值的状况下均为False {% if xo %} <p>xo有值</p> {% else %} <p>xo没有值</p> {% endif %} {% if xo %} <p>xo有值</p> {% elif xo1 %} <p>xo1有值</p> {% else %} <p>去他大爷的</p> {% endif %} if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。
当内置的过滤器或标签没法知足咱们需求时,咱们能够自定义,具体操做步骤以下
settings.py
# 在settings.py中找到该列表,而后加以配置 INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01.apps.App01Config', 'app01', # 添加当前app的名字 ]
在应用名下面新建一个templatetags文件夹(必须叫这个名字)
在该文件夹下 新建一个任意名称的py文件,在该py文件内自定义过滤器或标签
from django import template register = template.Library() # 注意变量名必须为register,不可改变 #一、自定义过滤器 @register.filter def my_multi_filter(v1 ,v2): # 自定义的过滤器只能定义最多两个参数,针对{{ value1 |filter_multi:value2 }},参数传递v1=value1,v2=value2 return v1 * v2 #二、自定义标签 @register.simple_tag def my_multi_tag(v1, v2): # 自定义的标签能够定义多个参数 return v1 * v2 #三、自定义标签扩展之mark_safe # 注释:咱们能够用内置的标签safe来让标签内容有语法意义,若是咱们想让自定义标签处理的结果也有语法意义,则不能使用内置标签safe了,须要使用mark_safe,能够实现与内置标签safe一样的功能 from django.utils.safestring import mark_safe @register.simple_tag def my_input_tag(id, name): res = "<input type='text' id='%s' name='%s' />" % (id, name) return mark_safe(res)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--必须先加载存有自定义过滤器和标签的文件--> {% load my_tags %} <!--salary的值为10, 通过滤器my_multi_filter的处理结果为120--> {{ salary|my_multi_filter:12 }} <!--结果为2--> {% my_multi_tag 1 2 %} <!--结果为一个input标签,该表的属性id="inp1" name="username" 注意: input的的属性值均为字符串;类型,因此my_input_tag后的;两个值均为字符串类型--> {% my_input_tag "inp1" "username" %} </body> </html>
#一、自定义过滤器只能传两个参数,而自定义标签却能够传多个参数 #二、过滤器能够用于if判断,而标签不能 {% if salary|my_multi_filter:12 > 200 %} {% else %} {% endif %}
在实际开发中,模板文件彼此之间可能会有大量冗余代码,为此django提供了专 门的语法来解决这个问题,主要围绕三种标签的使用:include标签、extends标签、 block标签.
#做用:在一个模板文件中,引入/重用另一个模板文件的内容, {% include '模版名称' %}
事先须要再模板中 经过block划定区域
{% block 区域名字 %}
{% endblock %} 子板中如何使用 {% extends '模板的名字'%} {% block 区域名字 %} <h1>登陆页面</h1> {% endblock %} 一个页面上 block块越多 页面的扩展性越高 一般状况下 都应该有三片区域 {% block css %} {% endblock %} {% block content %} {% endblock %} {% block js %} {% endblock %} 子板中还能够经过 {{ block.super }} 来继续使用母版的内容 模板的导入 当你写了一个特别好看的form表单 你想再多个页面上都使用这个form表单 你就能够将你写的form表单看成模块的形式导入 导入过来以后 就能够直接展现 {% include 模块名 %}
若是要查询orm语句内部真正的sql语句有两种方式
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level': 'DEBUG', }, }}
只要是queryset对象就能够无限制的点queryset对象的方法
如:queryset.filter().filter().filter()
Django测试环境搭建
django测试环境搭建 import os if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "one_search.settings") import django django.setup() # 能够在下面测试django任何的py文件
补充(知道就行):
import os if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "one_search.settings") import django django.setup() from app01 import models res = models.Book.objects.all() # 惰性查询,你不去找他要,他就一直不显示 print(res) 运行后若是数据库中的表没有数据,会提示,其中LIMIT表示限制一次拿多少条(参考分页)
1 、models.Book.objects.create(title='西游记',price=123.23,publish_date='2019- 10-24') 二、from datetime import date ctime = date.today() book_obj = models.Book(title='三国演义',price=666.66,publish_date=ctime) book_obj.save()
一、models.Book.objects.filter(pk=3).update(price=999.66) 二、book_obj = models.Book.objects.filter(pk=3).first() book_obj.title = '在这儿改数据' book_obj.save()
models.Book.objects.filter(pk=3).delete()
表
#1: .all() 查询全部 # 无参 # 返回值为QuerySet对象,QuerySet对象中包含了查询出的全部记录对象 res = models.Book.objects.all() # 惰性查询 print(res) for i in res: print(i.title) # 打印: res = <QuerySet [<Book: 就是要改你>, <Book: 三国演义>]> i.title = 就是要改你,三国演义 #2: filter() 过滤 QuerySet # 有参,参数为过滤条件 # 返回值为QuerySet对象,QuerySet对象中包含了符合过滤条件的多个记录对象 res = models.Book.objects.filter(pk=3)# 惰性查询 print(res) # 打印: <QuerySet [<Book: 就是要改你>]> #3: get(**kwargs) 数据对象自己 # 有参,参数为筛选条件 # 返回值为一个符合筛选条件的记录对象(有且只有一个),若是符合筛选条件的对象超过一个或者没有都会抛出错误。 res = models.Book.objects.get(pk=3) print(res) # 打印:就是要改你 #4:first() 拿第一个 # 无参 # 返回查询出的第一个记录对象 res = models.Book.objects.all() print(res) print(res.first()) # 打印: <QuerySet [<Book: 就是要改你>, <Book: 三国演义>]> 就是要改你 #5: last() 拿最后一个 # 无参 # 返回查询出的最后一个记录对象 res = models.Book.objects.all() print(res) print(res.last()) # 打印: <QuerySet [<Book: 就是要改你>, <Book: 三国演义>]> 三国演义 # 6.exclude 除此以外 QuerySet # 有参,参数为过滤条件 # 返回值为QuerySet对象,QuerySet对象中包含了不符合过滤条件的多个记录对象 res = models.Book.objects.exclude(pk=3).filter(pk=4).filter(pk=1).filter(pk=4) print(res) # 打印: <QuerySet []> # 7.values QuerySet 列表套字典 # 有参,参数为字段名,能够指定多个字段 # 返回值为QuerySet对象,QuerySet对象中包含的并非一个个的记录对象,而上多个字典,字典的key即咱们传入的字段名 res = models.Book.objects.values('title') for r in res: print(r.get('title')) # 打印: <QuerySet [{'title': '就是要改你'}, {'title': '三国演义'}]> 就是要改你 三国演义 # 8.values_list QuerySet 列表套元组 # 有参,参数为字段名,能够指定多个字段 # 返回值为QuerySet对象,QuerySet对象中包含的并非一个个的记录对象,而上多个小元组,字典的key即咱们传入的字段名 res = models.Book.objects.values_list('title') print(res) # 打印: <QuerySet [('就是要改你',), ('三国演义',)]> # 9.count() 统计数据的个数 # 无参 # 返回包含记录对象的总数量 res = models.Book.objects.count() res1 = models.Book.objects.all().count() print(res,res1) # 打印: 2 2 # 10.distinct() 去重 # 若是使用的是Mysql数据库,那么distinct()无需传入任何参数 # 从values或values_list的返回结果中剔除重复的记录对象,返回值为QuerySet对象 """去重:数据必须是如出一辙的状况下才能去重""" res = models.Book.objects.all().distinct() res1 = models.Book.objects.values('title','price').distinct() print(res1) # 打印: <QuerySet [{'title': '就是要改你', 'price': Decimal('999.66')}, {'title': '三国演义', 'price': Decimal('666.66')}]> # 11.order_by() # 有参,参数为排序字段,能够指定多个字段,在字段1相同的状况下,能够按照字段2进行排序,以此类推,默认升序排列,在字段前加横杆表明降序排(如"-id") # 返回值为QuerySet对象,QuerySet对象中包含了排序好的记录对象 res = models.Book.objects.order_by('price') # 默认是升序 res1 = models.Book.objects.order_by('-price') # 加负号就是降序 print(res) # 打印 看备注 # 12.reverse() 前面必须是先结果排序才能够反转 # 无参 # 对排序的结果取反,返回值为QuerySet对象 res = models.Book.objects.order_by('price').reverse() print(res) # 打印:<QuerySet [<Book: 就是要改你>, <Book: 三国演义>]> # 13.exists() # 无参 # 返回值为布尔值 res = models.Book.objects.filter(pk=1).exists() print(res) # 有查询的数据就返回True,没有就返回False
表:
# 查询价格大于200的书籍 res = models.Book.objects.filter(price__gt=200) print(res) # 打印: <QuerySet [<Book: 就是要改你>, <Book: 三国演义>, <Book: 老人与海>, <Book: 山海经>]> # 查询价格小于200的书籍 res = models.Book.objects.filter(price__lt=200) print(res) # 打印:<QuerySet [<Book: 计算机原理>]> # 查询价格大于或者等于200的书籍 res = models.Book.objects.filter(price__gte=200) res1 = models.Book.objects.filter(price__lte=200) print(res,res1) # 打印: <QuerySet [<Book: 就是要改你>, <Book: 三国演义>, <Book: 老人与海>, <Book: 山海经>]> <QuerySet [<Book: 计算机原理>]> # 价格是200 或者是123.23 或者666.66 res = models.Book.objects.filter(price__in=[200,123.23,666.66]) print(res) # 打印: <QuerySet []> # 价格在200 到700之间的书籍 res = models.Book.objects.filter(price__range=(200,666.66)) # 顾头不顾尾 print(res) # 打印: <QuerySet [<Book: 老人与海>]>
sql 原生语句使用模糊查询: like (%:匹配任意个数任意字符和 下划线 _ :匹配一个任意字符)
# 查询书籍名称中包含p的 res = models.Book.objects.filter(title__contains='p') # 区分大小写 print(res) # 打印 <QuerySet [<Book: python入门>]> # 忽略大小写 res = models.Book.objects.filter(title__icontains='P') # 忽略大小写 print(res) # 打印 <QuerySet [<Book: python入门>]> # 查询书籍名称是以三开头的书籍 res = models.Book.objects.filter(title__startswith='三') print(res) # 打印 <QuerySet [<Book: 三国演义>]> # 查询书籍名称是以你开头的书籍 res = models.Book.objects.filter(title__endswith='你') print(res) # 打印 <QuerySet [<Book: 就是要改你>]> # 查询出版日期是2019年的书籍 res = models.Book.objects.filter(publish_date__year='2017') print(res) # 打印 <QuerySet [<Book: 山海经>]> # 查询出版日期是10月的书籍 res = models.Book.objects.filter(publish_date__month='10') print(res) # 打印 <QuerySet [<Book: 就是要改你>, <Book: 三国演义>, <Book: 老人与海>, <Book: python入门>]>
from django.db import models # Create your models here. """ 你在写orm语句的时候 跟你写sql语句同样 不要想着一次性写完 写一点查一点看一点 """ class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(max_digits=8,decimal_places=2) publish_date = models.DateField(auto_now_add=True) # 书籍与出版社 是一对多关系 publish = models.ForeignKey(to='Publish') # 书籍与做者 是多对多 authors = models.ManyToManyField(to='Author') """ authors虚拟字段 1.告诉orm自动帮你建立第三张关系表 2.orm查询的时候 可以帮助你更加方便的查询 """ def __str__(self): return self.title class Publish(models.Model): name = models.CharField(max_length=32) addr = models.CharField(max_length=64) def __str__(self): return self.name """return返回的数据必须是字符串类型""" class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() # author_detail = models.ForeignKey(unique=True,to='AuthorDetail') author_detail = models.OneToOneField(to='AuthorDetail') def __str__(self): return self.name class AuthorDetail(models.Model): phone = models.BigIntegerField() addr = models.CharField(max_length=64)
# 首先在test文件中加入下面代码: import os if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "many_search.settings") import django django.setup() from app01 import models # 建立数据 models.Book.objects.create(title='三国演义',price=123.23,publish_id=1) # publish_id直接传出版社主键值 models.Book.objects.create(title='红楼梦',price=523.23,publish_id=3) # publish_id直接传出版社主键值 models.Book.objects.create(title='老人与海',price=23.23,publish_id=3) # publish_id直接传出版社主键值 publish_obj = models.Publish.objects.filter(pk=2).first() models.Book.objects.create(title='水浒传',price=123.23,publish=publish_obj) # publish直接传出版社数据对象
book_obj = models.Book.objects.filter(pk=1).first() print(book_obj.publish) # 获取到当前所对应的出版社对象 print(book_obj.publish_id) # 获取到的就是表中的实际字段 # 打印: 东海出版社 ,1
models.Book.objects.filter(pk=1).update(publish_id=3) publish_obj = models.Publish.objects.filter(pk=2).first() models.Book.objects.filter(pk=1).update(publish=publish_obj)
models.Publish.objects.filter(pk=2).delete() # 默认也是级联更新 级联删除
# 给主键为3的书籍添加两个做者 1 2 book_obj = models.Book.objects.filter(pk=3).first() # print(book_obj.authors) # 就至关于 已经在书籍和做者的关系表了 # book_obj.authors.add(1) # book_obj.authors.add(2,3) author_obj = models.Author.objects.filter(pk=1).first() author_obj1 = models.Author.objects.filter(pk=2).first() # book_obj.authors.add(author_obj) book_obj.authors.add(author_obj,author_obj1) """ add() 括号内既能够传数字也能够传数据对象而且都支持传多个 """
# 修改关系 book_obj = models.Book.objects.filter(pk=3).first() book_obj.authors.set([3,]) book_obj.authors.set([1,3]) author_obj = models.Author.objects.filter(pk=1).first() author_obj1 = models.Author.objects.filter(pk=2).first() book_obj.authors.set((author_obj,)) book_obj.authors.set((author_obj,author_obj1)) """ set() 括号内 既能够传数字也传对象 而且也是支持传多个的 可是须要注意 括号内必须是一个可迭代对象 """
book_obj = models.Book.objects.filter(pk=3).first() # book_obj.authors.remove(2) # book_obj.authors.remove(1,2) author_obj = models.Author.objects.filter(pk=1).first() author_obj1 = models.Author.objects.filter(pk=2).first() #book_obj.authors.remove(author_obj) book_obj.authors.remove(author_obj,author_obj1) """ remove() 括号内 既能够传数字也传对象 而且也是支持传多个的 """
book_obj = models.Book.objects.filter(pk=3).first() book_obj.authors.clear() """clear()括号内不须要传任何参数 直接清空当前书籍对象全部的记录"""
谁有外键字段谁就是正向
没有外键字段的就是反向
正向查询按字段,反向查询表名小写
书籍对象 查 出版社 外键字段在书籍 正向查询
出版社 查 书籍 外键字段书籍 反向查询
基于对象的跨表查询,子查询
基于双下划线的跨表查询 连表查询
步骤:先获取一个数据对性,而后利用对象点的方式查询到所对应的数据
表:app01_book
表:app01_book_authors
表:app01_author
表:app01_authordetail
表:app01_publish
# 1.查询书籍是三国演义的出版社名称 book_obj = models.Book.objects.filter(title='三国演义').first() # 正向查询按字段 print(book_obj.publish.name) print(book_obj.publish.addr) # 打印 山海出版社山海 #2.查询书籍主键是2的做者姓名 book_obj = models.Book.objects.filter(pk=2).first() print(book_obj.authors) app01.Author.Noneprint(book_obj.authors.all()) # 打印: app01.Author.None, <QuerySet [<Author: 钱>]> # 3.查询做者是赵的手机号 author_obj = models.Author.objects.filter(name='赵').first() print(author_obj.author_detail.phone) print(author_obj.author_detail.addr) # 打印: 110, 山东 """ 正向查询 按字段 当该字段所对应的数据有多个的时候 须要加.all() 否者点外键字段直接就可以拿到数据对象 """ # 4.查询出版社是山海出版社出版过的书籍 publish_obj = models.Publish.objects.filter(name='山海出版社').first() print(publish_obj.book_set) app01.Book.Noneprint(publish_obj.book_set.all()) # 打印 app01.Book.None, <QuerySet [<Book: 三国演义>, <Book: 水浒传>]> # 5.查询做者是jason写过的全部的书 author_obj = models.Author.objects.filter(name='jason').first() print(author_obj.book_set) app01.Book.Noneprint(author_obj.book_set.all()) # 打印app01.Book.None, <QuerySet [<Book: 三国演义>]> # 6.查询手机号是110的做者 author_detail_obj = models.AuthorDetail.objects.filter(phone=110).first() print(author_detail_obj.author) print(author_detail_obj.author.name) print(author_detail_obj.author.age) # 打印: 赵, 赵, 18 """ 反向查询按表名小写 何时须要加_set 当查询的结果能够是多个的状况下 须要加_set.all() 何时不须要加_set 当查询的结果有且只有一个的状况下 不须要加任何东西 直接表名小写便可""" # 7.查询书籍是python入门的做者的手机号 book_obj = models.Book.objects.filter(title='三国演义').first() print(book_obj.authors.all()) # 打印 <QuerySet [<Author: 赵>]> # 2.基于双下划綫的跨表查询 连表查询 """MySQL left join inner join right join union """ # 1.查询书籍是三国演义的出版社名称正向 res = models.Book.objects.filter(title='三国演义').values('publish__name') print(res) # 打印: <QuerySet [{'publish__name': '山海出版社'}]> # 反向 res = models.Publish.objects.filter(book__title='三国演义').values('name') print(res) # 打印: <QuerySet [{'name': '山海出版社'}]> # 2.查询做者是李的手机号码正向 res1 = models.Author.objects.filter(name='李').values('author_detail__phone') print(res1) # 打印:<QuerySet [{'author_detail__phone': 114}]> # 反向 res = models.AuthorDetail.objects.filter(author__name='jason').values('phone','author__age') print(res) # 打印:<QuerySet [{'phone': 114, 'author__age': 21}]> # 3.查询手机号是120的做者姓名 res2 = models.AuthorDetail.objects.filter(phone=120).values('author__name') print(res2) # 打印: <QuerySet [{'author__name': '钱'}]> res = models.Author.objects.filter(author_detail__phone=120).values('name','author_detail__addr') print(res) # 打印: <QuerySet [{'name': '钱', 'author_detail__addr': '河北'}]> # 4.查询出版社是山海出版社出版的书籍名称 res = models.Publish.objects.filter(name='山海出版社').values('book__title','addr') print(res) # 打印:<QuerySet [{'book__title': '三国演义', 'addr': '山海'}, {'book__title': '水浒传', 'addr': '山海'}]> # 5.查询做者是钱的写过的书的名字和价格 res = models.Author.objects.filter(name='钱').values('book__title','book__price')print(res) # 打印: <QuerySet [{'book__title': '红楼梦', 'book__price': Decimal('523.23')}]> # 6.查询书籍是三国演义的做者的手机号 res = models.Book.objects.filter(title='三国演义').values('authors__author_detail__phone') print(res) # 打印: <QuerySet [{'authors__author_detail__phone': 110}]>
关键字:aggregate
# 导入模块 from django.db.models import Max,Min,Sum,Count,Avg res = models.Book.objects.all().aggregate(Avg('price')) # 求全部书的平均价格 res1 = models.Book.objects.all().aggregate(Max('price')) # 求全部书的最大价格 res2 = models.Book.objects.all().aggregate(Min('price')) # 求全部书的最小价格 res3 = models.Book.objects.all().aggregate(Sum('price')) # 求全部书的价格和 res4 = models.Book.objects.all().aggregate(Count('title')) # 求全部书的计数 res5 = models.Book.objects.all().aggregate(Avg('price'),Max('price'),Min('price'),Sum('price'),Count('title')) print(res5) # 打印: {'price__avg': 198.73, 'price__max': Decimal('523.23'), 'price__min': Decimal('23.23'), 'price__sum': Decimal('794.92'), 'title__count': 4}
关键字:annotate
# 1.统计每一本书的做者个数 res = models.Book.objects.annotate(author_num=Count('authors')).values('author_num') print(res) # 打印: <QuerySet [{'author_num': 1}, {'author_num': 1}, {'author_num': 1}, {'author_num': 1}]> # 2.统计出每一个出版社卖的最便宜的书的价格 res = models.Publish.objects.annotate(price_min=Min('book__price')).values('price_min') print(res) # 打印: <QuerySet [{'price_min': Decimal('23.23')}, {'price_min': Decimal('123.23')}, {'price_min': None}]> # 3.统计不止一个做者的图书 """ 步骤: 1.统计每本书对应的做者个数 2.基于上面的结果 筛选出做者个数大于1 的 """ res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('author_num') print(res) # 打印: <QuerySet []> # 4.查询各个做者出的书的总价格 res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('sum_price') print(res) # 打印: <QuerySet [{'sum_price': Decimal('125.23')}, {'sum_price': Decimal('523.23')}, {'sum_price': Decimal('23.23')}, {'sum_price': Decimal('123.23')}]>
from django.db.models import F, Q # 1.查询出卖出数大于库存数的书籍 res = models.Book.objects.filter(maichu__gt=F('kucun')) print(res) # 打印: <QuerySet []> # 2.将全部的书的价格 所有提升100块 models.Book.objects.update(price=F('price') + 100)
Q:
res = models.Book.objects.filter(title='三国演义', price=123.33) # 逗号就是and res1 = models.Book.objects.filter(Q(title='三国演义'), Q(price=544.44)) # 逗号就是and res2 = models.Book.objects.filter(Q(title='三国演义') | Q(kucun=666)) # 用来Q以后 就可以支持|表示或 res3 = models.Book.objects.filter(~Q(title='三国演义') | Q(kucun=666)) # esc下面那个键 波浪号 表示非 print(res) print(res1) print(res2) print(res3) # 打印结果: <QuerySet []>, <QuerySet []>, <QuerySet [<Book: 三国演义>], <QuerySet [<Book: 红楼梦>, <Book: 水浒传>, <Book: 老人与海>]>
q = Q() q.connector = 'or' q.children.append(('title__icontains','三')) q.children.append(('kucun',666)) res = models.Book.objects.filter(q) print(res) """ 字符串的左边 跟变量名条件书写如出一辙 """ # 打印: <QuerySet [<Book: 三国演义>]>
only会将括号内的字段对应的值 直接封装到返回给你的对象中 点该字段 不须要再走数据库一旦你点了不是括号内的字段 就会频繁的去走数据库查询
ORM经常使用字段:
AutoField int自增列,必须填入参数 primary_key=True。当model中若是没有自增列,则自动会建立一个列名为id的列。 IntegerField 一个整数类型,范围在 -2147483648 to 2147483647。(通常不用它来存手机号(位数也不够),直接用字符串存,) CharField 字符类型,必须提供max_length参数, max_length表示字符长度. DateField 日期字段,日期格式 YYYY-MM-DD,至关于Python中的datetime.date()实例。 DateTimeField 日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],至关于Python中的datetime.datetime()实例。
这里须要知道的是Django中的CharField对应的MySQL数据库中的varchar类型,没有设置对应char类型的字段,可是Django容许咱们自定义新的字段,下面我来自定义对应于数据库的char类型
from django.db import models # Create your models here. #Django中没有对应的char类型字段,可是咱们能够本身建立 class FixCharField(models.Field): ''' 自定义的char类型的字段类 ''' def __init__(self,max_length,*args,**kwargs): self.max_length=max_length super().__init__(max_length=max_length,*args,**kwargs) def db_type(self, connection): ''' 限定生成的数据库表字段类型char,长度为max_length指定的值 :param connection: :return: ''' return 'char(%s)'%self.max_length #应用上面自定义的char类型 class Class(models.Model): id=models.AutoField(primary_key=True) title=models.CharField(max_length=32) class_name=FixCharField(max_length=16) gender_choice=((1,'男'),(2,'女'),(3,'保密')) gender=models.SmallIntegerField(choices=gender_choice,default=3)
字段合集:
AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) - bigint自增列,必须填入参数 primary_key=True 注:当model中若是没有自增列,则自动会建立一个列名为id的列 from django.db import models class UserInfo(models.Model): # 自动建立一个列名为id的且为自增的整数列 username = models.CharField(max_length=32) class Group(models.Model): # 自定义自增列 nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) SmallIntegerField(IntegerField): - 小整数 -32768 ~ 32767 PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正小整数 0 ~ 32767 IntegerField(Field) - 整数列(有符号的) -2147483648 ~ 2147483647 PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正整数 0 ~ 2147483647 BigIntegerField(IntegerField): - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807 BooleanField(Field) - 布尔值类型 NullBooleanField(Field): - 能够为空的布尔值 CharField(Field) - 字符类型 - 必须提供max_length参数, max_length表示字符长度 TextField(Field) - 文本类型 EmailField(CharField): - 字符串类型,Django Admin以及ModelForm中提供验证机制 IPAddressField(Field) - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制 GenericIPAddressField(Field) - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6 - 参数: protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6" unpack_ipv4, 若是指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启此功能,须要protocol="both" URLField(CharField) - 字符串类型,Django Admin以及ModelForm中提供验证 URL SlugField(CharField) - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、链接符(减号) CommaSeparatedIntegerField(CharField) - 字符串类型,格式必须为逗号分割的数字 UUIDField(Field) - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证 FilePathField(Field) - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能 - 参数: path, 文件夹路径 match=None, 正则匹配 recursive=False, 递归下面的文件夹 allow_files=True, 容许文件 allow_folders=False, 容许文件夹 FileField(Field) - 字符串,路径保存在数据库,文件上传到指定目录 - 参数: upload_to = "" 上传文件的保存路径 storage = None 存储组件,默认django.core.files.storage.FileSystemStorage ImageField(FileField) - 字符串,路径保存在数据库,文件上传到指定目录 - 参数: upload_to = "" 上传文件的保存路径 storage = None 存储组件,默认django.core.files.storage.FileSystemStorage width_field=None, 上传图片的高度保存的数据库字段名(字符串) height_field=None 上传图片的宽度保存的数据库字段名(字符串) DateTimeField(DateField) - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] DateField(DateTimeCheckMixin, Field) - 日期格式 YYYY-MM-DD TimeField(DateTimeCheckMixin, Field) - 时间格式 HH:MM[:ss[.uuuuuu]] DurationField(Field) - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型 FloatField(Field) - 浮点型 DecimalField(Field) - 10进制小数 - 参数: max_digits,小数总长度 decimal_places,小数位长度 BinaryField(Field) - 二进制类型 对应关系: 'AutoField': 'integer AUTO_INCREMENT', 'BigAutoField': 'bigint AUTO_INCREMENT', 'BinaryField': 'longblob', 'BooleanField': 'bool', 'CharField': 'varchar(%(max_length)s)', 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 'DateField': 'date', 'DateTimeField': 'datetime', 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 'DurationField': 'bigint', 'FileField': 'varchar(%(max_length)s)', 'FilePathField': 'varchar(%(max_length)s)', 'FloatField': 'double precision', 'IntegerField': 'integer', 'BigIntegerField': 'bigint', 'IPAddressField': 'char(15)', 'GenericIPAddressField': 'char(39)', 'NullBooleanField': 'bool', 'OneToOneField': 'integer', 'PositiveIntegerField': 'integer UNSIGNED', 'PositiveSmallIntegerField': 'smallint UNSIGNED', 'SlugField': 'varchar(%(max_length)s)', 'SmallIntegerField': 'smallint', 'TextField': 'longtext', 'TimeField': 'time', 'UUIDField': 'char(32)',