Django_day03

视图层

三板斧

'''
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条

必知必会131.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  获取你想获取的值
	
'''
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值