文章目录
视图层
三板斧
'''
HttpResponse
返回字符串类型
render
返回html页面 并且在返回给浏览器之前还可以给html文件传值
redirect
重定向
'''
视图函数必须返回一个HttpResponse对象
除了HttpResponse不说 render、redict 都是有继承HttpResponse
# render简单内部原理
from django.template import Template,Context
res = Template('<h1>{{ user }}</h1>')
con = Context({'user':{'username':'jason','password':123}})
ret = res.render(con)
print(ret)
return HttpResponse(ret)
JsonResponse对象
json格式的数据有什么用?
前后端数据交互需要使用到json作为过渡 实现跨语言传输数据
'''
import json
from django.http import JsonResponse
def ab_json(request):
user_dict = {"username":"jason", "password":"1234", "hobby":"girl"}
l = [11, 22, 33, 44]
# 先转成json格式字符串
# 方法一: # 前端数据是双引号 那就是json数据
# json_str = json.dumps(user_dict, ensure_ascii=False)
# return HttpResponse(json_str)
# 方法二:
# 该方法会自动转码 通过读源码 掌握用法 然后取消自动转码
# return JsonResponse(user_dict, json_dumps_params={'ensure_ascii': False})
# 学会读报错信息
# 'In order to allow non-dict objects to be serialized set the safe parameter to False'
return JsonResponse(l, safe=False)
'''
JsonResponse默认只能序列化字典 序列化其他需要加safe参数 safe=False
'''
前端序列化
JSON.stringify() json.dumps()
JSON.parse() json.loads()
form表单上传文件及后端如何获取
上传文件需要指定的两个参数
mehtod='post'
enctype=formdata
def ab_file(request):
if request.method == "POST": # 注意 这里是 request.method == "POST"
print(request.POST) # 只能获取普通的键值对数据 文件不行
print(request.FILES) # 能拿到文件
file_obj = request.FILES.get("file") # 文件对象
print(file_obj.name)
with open(file_obj.name, "wb") as fp: # 通过循环遍历每行二进制文件进行读取
for file in file_obj:
fp.write(file)
return render(request, 'form.html')
request对象方法
'''
request.method
request.POST
request.GET
request.FILES
request.path
request.get_full_path()
request.body 原生的浏览器发过来的二进制数据
'''
print(request.path) # 上面这两行方法只能拿到路由 没办法拿到路由后面的参数
print(request.path_info)
print(request.get_full_path()) # 这个 路由和参数都有拿到
FBV与CBV
视图函数既可以是函数也可以是类
'''FBV'''
def index(request):
return HttpResponse('index')
'''CBV'''
from django.views import View
class Mylogin(View):
def get(self, request): # 访问到该路由 如果是get方式 那么就走这里
return render(request, 'form.html')
def post(self, request): # 访问该路由 如果是post方式 就走这里 这样比用 if request.method == "POST" 方便
return HttpResponse('post方法')
'''路由与视图的书写
re_path(r'^login/', views.Mylogin.as_view()) view要写()
'''
FBV和CBV各有千秋
CBV特点
能够直接根据请求方式的不同直接匹配到对应的方法执行
内部到底怎么实现的?
CBV内部源码
CBV源码刨析
刨析入口通过这个
re_path(r'^login/', views.MyLogin.as_view())
'''
因为MyLogin有继承View类 而我们写的类中并没有as_view()方法 因此这个方法是View类中的方法
因为这里并没有创建实例对象 这个方法也能通过类调用的话 那就有两种可能 类方法 或者 静态方法
通过源码查看 可知是类方法
@classonlymethod
def as_view(cls, **initkwargs):
而通过看该函数的内部代码 内部定义了一个函数view 且用到了名称空间cls 所以是一个闭包函数 且 as_view()函数return view 意思就是返回闭包函数的函数名
所以我们要看as_view()函数里面的view()函数执行了什么
return self.dispatch(request, *args, **kwargs)
这句 self.dispatch 第一反应就是self是谁的 (这个函数的 不是 该函数没有 dispatch关键字, 调用该函数的类(MyLogin类的) 也不是 最后再看MyLogin类的父类View类的 是 在该类中找到了 dispatch函数)
dispatch函数关键代码 也是CBV精髓 用到了反射
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
'''
通过观察dispatch函数 大概了解它会先判断我们的request.method 是否符合八个请求方式['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
若是符合返回对应请求方式的小写 get/post 名称 然后就会去到MyLogin类中执行我们对应写的get/post 方法
模板语法传值
{{}}:变量相关
{% %}: 逻辑相关
'''
python 所有的基础类型 都可以传递
整数 浮点数 字符串 列表 元组 字典 集合
传递函数 和类名的时候 会自动加括号调用 但是模板语法不支持给函数传额外参数
{{ func }} {{MyClass}}
其内部会自动判断当前的变量名是否可以加括号调用 如果可以就会自动执行 针对的是函数名与类名
'''
django模板语法的取值 只能采用 .的形式
d.username
l.0
d.hobby.3.info
既可以点键也可以点索引 还可以两者混用
过滤器
过滤器就类似于是模板语法内置的 内置方法
django内置有60多个过滤器 了解十个左右就差不多 以后遇到再去了解记忆
基本语法
{{数据|过滤器:参数}}
转义
# 前端
|safe
# 后端
from django.utils.safestring import mark_safe
res = mark_safe('<h1>纯纯</h1>')
'''
以后你在写全栈项目的时候 前端代码不一定非要在前端页面书写
也可以先在后端写好 然后传递给前端页面
'''
<h1>过滤器</h1>
<p>统计长度:{{ s|length }}</p>
<p>第一个参数是True就展示参数的值 否则就展示default后面跟的默认值:{{ r|default:'我是默认值' }}</p>
<p>文件大小:{{ file_size|filesizeformat }}</p>
<p>日期格式化:{{ current_time|date:'Y-m-d H:i:s' }}</p>
<p>切片操作(支持步长):{{ s|slice:'0:4:2' }}</p>
<p>切取字符:{{ s|truncatechars:3 }}</p> <!-- 后面的数字代表只展示多少个字符 后面会自动跟...三个点 这三个点在django1.x版本就占了3个字符 (算在你的数字里面) django2.x只占一个字符-->
<p>切取单词(不包含三个点 只按照空格切):{{ name|truncatewords:9 }}</p>
<p>移除特定的字符(把空格切掉 意思就是合并):{{ name|cut:' ' }}</p>
<p>拼接操作:{{ l|join:'$' }}</p>
<p>拼接操作加法(字符串相加 不是数值相加): {{ n|add:10 }}</p>
<p>取消转义(前端):{{ hhh|safe }}</p>
<p>取消转义(后端):{{ res }}</p>
标签
# for 循环
<h1>标签</h1>
{% for baby in l %}
{# {{ forloop }}#}
{{ baby }}
{% endfor %}
# if判断
{% if r %}
<p>baby</p>
{% elif %}
xxx
{% else %}
<p>old babay </p>
{% endif %}
# 混合使用
{% for baby in ll %}
{% if t %}
<p>{{baby}}</p>
{% elif F%}
<p>baby</p>
{% else %}
<p>old babay </p>
{% endif %}
{% empty %} 如果要迭代的内部是空的 那么就执行这个
<p>列表是空的</p>
{% endfor %}
# 取别名
{% with name as nb %}
<p>{{ nb }}</p>
假设这里的name里面有很多层数据 你要获取里面的数据 那只能通过. 的方式获取 因此可以这样去别名 在该{} 里面都可以用该别名
{% endwith %}
自定义过滤器、标签、inclusion_tag
'''
三步走
1.在应用下创建一个名字“必须”叫templatetags文件夹
2.在该文件夹内创建任意名称 的py文件
3.在该py文件内必须先书写下面两句话
from django import template
register = template.Library()
''' -----------------------
自定义过滤器
from django import template
register = template.Library()
@register.filter(name='baby')
def my_sum(v1,v2):
return v1+v2
使用
<h1>自定义的使用( 过滤器最多只有两个参数 )</h1>
{% load mytag %}
<p>{{ n|baby:666 }}</p>
# 自定义inclusion_tag
'''
内部原理
先定义一个方法
在页面上调用该方法 并且可以传值
该方法会生成一些数据 然后传递给一个html页面
之后将渲染好的结果放到调用好的位置
'''
模板的继承
'''
模板的继承 你自己先选好一个你想要继承的模板页面
{% entends 'home.html' %}
继承了之后子页面跟模板页面长的一模一样 你需要自己划分区域
{% block content %}
模板内容
{% endblock %}
子页面就可以声明想要修改哪块划定了的区域
{% block conent %}
子页面内容
{% endblock %}
'''
一般情况下模板页面上应该至少有三块可以被修改的区域
1.css区域
2.html区域
3.js区域
{% block css %}
{% endblock %}
{% block content %}
{% endblock %}
{% block js %}
{% endblock %}
这样每一个子页面都可以由自己独有的css代码 html代码 和js代码
模板的导入
'''
将页面的某一个局部当成模块的形式
哪个地方需要就可以直接导入使用即可
'''
{% include 'wasai.html' %}
单表操作
# django自带的sqlite3数据库对日期格式不是很敏感 处理的时候很容易出错
# 增
# 方式一
# res = models.User.objects.create(name='jason', age=19, register_time='2021-6-4')
# print(res) # 对象其本身
import datetime
# # 方式二
# ctime = datetime.datetime.now()
# user_obj = models.User(name='egon', age=44, register_time=ctime)
# user_obj.save()
# 删
# 方法一
# res = models.User.objects.filter(pk=2).delete()
# print(res)
'''pk会自动查找到当前表的主键 指代的就是当前表的主键字段
用了pk之后 你就不需要知道当前表的主键是什么了'''
# 方法二
# uesr_obj = models.User.objects.filter(pk=1).first()
# uesr_obj.delete()
# 修改
# 方法一
# models.User.objects.filter(pk=4).update(name='wcc')
# 方法二
# user_obj = models.User.objects.filter(pk=4).first() # .first() 才是拿到数据对象 从而可以进行 .属性= 的操作
# user_obj.name = 'egonPPP'
# user_obj.save()
# print(user_obj)
'''get方法返回的直接是当前数据的对象
但是该方法不推荐使用
一旦数据不存在 直接报错
而filter就不会'''
测试脚本
'''
当你只是想测试django中的某一个py文件内容 那么你可以不用书写前后端交互的形式
而是直接写一个测试脚本即可
脚本代码无论是写在应用下的tests.py 还是自己定义的.py文件 只要加上拷贝的三行代码和自己加上的两行代码 就都可以进行单独运行
'''
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'day05.settings')
# 这之上的三行代码都是从manage.py文件中拷贝的 下面两行需要自己手动输入
import django
django.setup()
# 在这个代码块的下面就可以测试django里面的单个py文件
查看内部sql语句的方式
方式一
res = models.User.objects.values_list('name', 'age')
print(res.query) # 可以查看内部封装的sql语句
'''上述查看sql语句的方式 只能用于queryset对象
只有该对象才能通过 .query的方式查看内部sql语句
'''
方式2
所有的sql语句都能查看
配置一下settings.py 文件就行了 配置网上搜一下就行了
必知必会13条
必知必会13条
1.all() 查询所有
2.filter() 带有过滤条件的查询
3.get() 直接拿取数据对象 但是条件不存在 直接报错
4.first() 拿queryset里面第一个元素
5.last() 拿queryset里面最后一个元素
6.values() 返回结果是列表套字典
res = models.User.objects.values('name', 'age') # 只会拿到每一条数据的name字段和age字段
print(res)
7.values_list() 返回结果是列表套元组
res = models.User.objects.values_list('name', 'age')
print(res.query) # 可以查看内部封装的sql语句
'''上述查看sql语句的方式 只能用于queryset对象
只有该对象才能通过 .query的方式查看内部sql语句
'''
8.distinct() 去重 只是输出去重 不是在数据库删除重复数据
res = models.User.objects.values('name', 'age').distinct()
print(res)
'''
去重一定要是一模一样的数据 id不一样也不行
'''
9.order_by()
res = models.User.objects.order_by('age') # 默认升序
res = models.User.objects.order_by('-age') # 降序
print(res)
10. reverse()
res = models.User.objects.order_by('age').reverse() # 要使用reverse必须是排好序了的
print(res)
11.count() # 统计当前数据的个数
res = models.User.objects.count()
res2 = models.User.objects.all().count() # 两种方法都行
print(res)
12.exclude() # 排除在外
res = models.User.objects.exclude(name='jason')
print(res)
13.exist() # 基本遇不到
res = models.User.objects.filter(pk=10).exists()
print(res)
神奇的双下滑线查询
# 神奇的双下滑线查询
# 年龄大于25岁的数据
res = models.User.objects.filter(age__gt=25) # 字段名__gt = 25 意思就这个字段 大于25 的数据
print(res)
# 年龄小于25岁的数据
res = models.User.objects.filter(age__lt=25)
print(res)
# 大于等于 小于等于
res = models.User.objects.filter(age__gte=22)
print(res)
res = models.User.objects.filter(age__lte=22)
print(res)
# 年龄是18 或者32 或者 40
res = models.User.objects.filter(age__in=[18, 32, 40])
print(res)
# 年龄在38至 40岁之间的 首位都要
res = models.User.objects.filter(age__range=[18, 40])
print(res)
# 查询出名字里面含有n的数据 模糊查询
res = models.User.objects.filter(name__contains='p')
print(res)
'''这个查询是区分大小写的'''
# 忽略大小写
res = models.User.objects.filter(name__icontains='p') # 区分大小写
print(res)
res = models.User.objects.filter(name__startswith='j') # __startwith = '' 筛选以什么开始的数据
res = models.User.objects.filter(name__endswith='j') # __endwith = '' 筛选以什么为结束的数据
# 查询出注册时间是 2021 6 月的
res = models.User.objects.filter(register_time__month='6') # 拿月份为6的数据
res = models.User.objects.filter(register_time__day='4') # 拿 日 为4的数据
print(res)
一对多外键增删改
一对多外键增删改查
增
1.直接写实际字段 id
models.Book.objects.create(title='论语', price=188.88, publish_id=1) # 这里的publish_id 是表里真实的字段
models.Book.objects.create(title='聊斋', price=256.98, publish_id=2) # 这里的publish_id 是表里真实的字段
models.Book.objects.create(title='老子', price=348.15, publish_id=1) # 这里的publish_id 是表里真实的字段
2. 虚拟字段 放对象 django会自动找到该对象的id然后 换成id值
publish_obj = models.Publish.objects.filter(pk=2).first() # 这是一个出版社对象
models.Book.objects.create(title='红楼梦', price=212.19, publish=publish_obj) # 放对象
删
models.Publish.objects.filter(pk=1).delete() # 级联删除 删除掉出版社 对应绑定了出版社id的book记录也会没
修改
models.Book.objects.filter(pk=4).update(id=3)
publish_obj = models.Publish.objects.filter(pk=1).first()
models.Book.objects.filter(pk=1).update(publish=publish_obj)
多对多 外键增删改
多对多 增删改查 就是操作第三张关系表
如何给书籍添加作者?
book_obj = models.Book.objects.filter(pk=2).first()
print(book_obj.authors) # 类似于你已经到了第三张表了
book_obj.authors.add(1) # 书籍id为1的书籍绑定一个id为1 的作者
book_obj.authors.add(2, 3) # 多表查询 因此一本书可以绑定多个作者
author_obj1 = models.Author.objects.filter(pk=1).first()
author_obj2 = models.Author.objects.filter(pk=2).first()
author_obj3 = models.Author.objects.filter(pk=3).first()
book_obj.authors.add(author_obj2,author_obj3)
'''
add
括号内 既可以传数字也可以传 对象就 并且支持多个
'''
删
book_obj.authors.remove(2)
book_obj.authors.remove(1, 3)
author_obj2 = models.Author.objects.filter(pk=2).first()
author_obj3 = models.Author.objects.filter(pk=3).first()
book_obj.authors.remove(author_obj2, author_obj3)
'''
remove
括号内 既可以传数字也可以传 对象就 并且支持多个
'''
改
book_obj.authors.set([1,2]) # 括号内必须是可迭代对象
book_obj.authors.set([3]) # 也可以是一个 set就像更新删除 让表里面的关系与 set里面保持一样 不管之前有几条绑定关系 set([3])后都只有和3的关系了
author_obj1 = models.Author.objects.filter(pk=1).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
book_obj.authors.set([author_obj2,author_obj1])
''''
add
括号内必须传一个可迭代对象, 该对象内既可以传数字也可以传对象,并且支持多个
先删除 后新增
'''
清空
在第三章关系表中 清空某一个书籍与作者的绑定关系
book_obj.authors.clear()
'''
clear
括号内不要加任何参数
'''
正反向的概念
# 正向
外键字段在我手上 那么,我查你就是正向
外键字段如果不在手上,我查你就是反向
book >>> 外键字段在书这儿(正向)>>> publish
publish >>> 外键字段在书那儿(反向)>>>book
# 反向
一对一和多对多正反向的判断也是如此
多表查询
'''
正向查询,看字段
反向查询,看表名
正向查询 (通过什么查什么)
先获取已知条件的对象(通过id)
book_obj = models.Book.objects.filter(id=1).first() 获取改对象
正向查询可以直接.绑定的字段 即可获取到 绑定对象
res = book_obj.publish 就可以获取到出版社对象
res.xxx 就可以获取到你想查询的值
反向查询
author_obj = models.Author.objects.filter(name='jason').first() 还是先获取对象
res = author_obj.book_set.all() # 反向查询也是点的方式 不过是小写 还要加上 _set 且如果你查询的对象有多个值 就要再加上 .all()
获取到关联的res 就可以通过res.xxx 获取你想获取的值
'''