Django——多层,,CBV和FBV,, 执行流程__源码分析,,django模版修改的视图函数,,页面静态化,,内置过滤器,,绑定给类的方法

Django分了很多层

  路由曾

  视图层 请求对象和响应对象

  模板曾

  模型层:orm:表单,多表,各种查询

  ajax forms组件  分页器  cookie session   中间件  auth

——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————视图层响应对象

  响应本质都是HttpReponse

  HttpReponse---字符串

  render-------放个模板   模板渲染是在后端完成的

  js代码实在客户端浏览器里执行的   

  模板语法是在后端执行的

  redirect---------重定向

  -字符串参数部分是空的

  状态码是  3开头   status=201

  JsonResponse   json格式数据

    return JsonResponse({name:lqz,age:19})

      本质是把传入的字典或列表(必须指定safe =False),使用 json序列化得到 json格式字符串----最终做成 HttpResponse返回给前端----- 如果想给 json序列化的时候,传参数,必须使用  json_dumps_params字典传入

      如果想往响应头中写数据---需要传headers = {‘xx’:‘xx’}

 

    JsonResponse源码分析

    return JsonResponse({name:lqz,age:19})       注:如果是列表   那么safe要改成 False  否则会抛异常

触发 JSonResponse的__init__ ----------{name:lqz,age:19} 给了data  

def __init__(self, data, encoder=DjangoJSONEncoder,

safe=True,json_dumps_params=None, **kwargs):

   如果传入的四字典
   safe是True,后面是False,条件不符合,内部就不会走
  if safe and not isinstance(data, dict):
    raise TypeError(
      'In order to allow non-dict objects to be serialized set the '
      'safe parameter to False.'
    )
  if json_dumps_params is None: # 条件符合
    json_dumps_params = {}
     kwargs是字典---》setdefault--》有则修改,无则新增
    kwargs.setdefault('content_type', 'application/json')
     核心---》把字典转成json格式字符串,赋值给data
  data = json.dumps(data, cls=encoder, **json_dumps_params)
   super().__init__ 调用父类的 __init__ 完成实例化---》HttpResponse的对象
  return HttpResponse(data,**kwargs)
  super().__init__(content=data, **kwargs)

isinstance 

  isinstance(对象,类)判断这个对象,是不是这个类的对象

 

CBV和FBV

  FBV:基于函数的视图

        之前的都是FBV

    CBV写法 

  from django.views import View

  class UserView(View):

    写方法---跟请求方式同名的方法

  def get(self,request,*args,**kwargs)

      必须返回四件套

路由配置:

  path('index/', 视图类名.as_view())    as_view是类的绑定方法

 

执行流程--》源码分析
path('index/', index),--->请求来了,路由匹配成功会执行 index(request,)
path('index/', UserView.as_view()),
  1 入口:路由---》as_view来开始
  -请求来了,路由匹配成功---》执行---》UserView.as_view()(request)
  -需要看as_view()执行结果是什么--》view--》代码如下
    def view(request, *args, **kwargs): # 方法,可以加括号调用
      return self.dispatch(request, *args, **kwargs)
  -本质就是在执行 view(request)
  -本质在执行---》self.dispatch(request, *args, **kwargs)
  -去类(UserViwe类中找,找不到,去父类View)中找dispatch,代码如下
  def dispatch(self, request, *args, **kwargs):
     request当次请求的请求对象,取出请求方式【假设是get请求】,转成小写 'get'
     http_method_names = ['get', 'post', 'put']
     条件成立,执行if内部代码
    if request.method.lower() in self.http_method_names:
      getattr:反射---》通过字符串去对象中取属性或方法
       self是谁的对象? 是View这个类的对象,这个是视图类UserView的对象
       取出来的handler 是 UserView这个类的get方法
      handler = getattr(self, 'get')
    else:
      handler = self.http_method_not_allowed
     handler是 UserView这个类的get方法
     get(request)---》触发UserView这个类的get方法---》真正执行原来视图函数的内容
     最终返回
    return handler(request, *args, **kwargs)

 总结:写cbv,只需要在视图类中写跟请求方式同名的方法即可--》不同请求方式,就会执行不同的方法

 

关于类中self是谁的问题

  

class Animal:
  def run(self):
     这个self,是谁调用,就是谁
    print(type(self))
    print(self.name, '走路')


class Person(Animal):
  def __init__(self, name):
    self.name = name

class Dog(Animal):
  def __init__(self, name,age):
    self.name = name
    self.age=age
 p = Person('lqz')
 p.run() #

dog=Dog('小奶狗',6)
dog.run()

 self 是谁调用。self就是谁,不能只看是哪个类

 

上传文件

关于模板查找路径是配置文件中
TEMPLATES --->'DIRS': [os.path.join(BASE_DIR, 'templates')]


## python
class FileView(View):
  def get(self,request):
    return render(request,'file.html')
  def post(self,request):
     拿出文件对象
    my_file=request.FILES.get('myfile')
    print(type(my_file)) 

  

 my_file=request.FILS.egt('myfile')     

        通过 print(type('my_file'))查看类型

    #django.core.files.uploadedfile.InMemoryUploadedFile 跟之前用的文件对象不一样但是,它应该继承了文件
    from django.core.files.uploadedfile import InMemoryUploadedFile
   

     1 保存 2 取出文件名字
     my_file.save() #找了一顿,没有,所以不能使用(save)快捷保存方式,需要自己写保存
    print(my_file.name)    看neme属性是不是 这个文件的名字

    3-xxxxx.md
     自己写保存,放在项目根路径下
    with open(my_file.name,'wb') as f:
      for line in my_file:
        f.write(line)
    return HttpResponse('上传成功')

html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>

</head>
<body>
<form action="" (默认当前地址)method="post" enctype="multipart/form-data"> --编码格式
  <input type="file" name="myfile">
  <br>
  <input type="submit" value="提交">  目前记得注掉 srf
</form>
</body>
</html>

此时点post提交 会报错

需要写  def post(self,request):

    拿出文件

    my_file=request.FILS.egt('myfile')     

        通过 print(type('my_file'))查看类型

 

模板 templease.html

模板在浏览器中运行不了,因为它有模板语法  浏览器解析不了模板语法

必须在后端渲染完成(替换完成) 变成纯粹的html,css,js

这种在后端会被渲染 类python语法 它叫模板语法   django中它又叫 dtl: django template  language

 

django模板修改的视图函数

了解####
# ================================django模板修改的视图函数
from django.template import Template,Context
now=datetime.datetime.now()
# 内部打开了这个模板---》读出所有内容,实例化得到了t对象
t=Template('<html><body>现在时刻是:<h1>{{current_date}}</h1></body></html>')
# #t=get_template('current_datetime.html')
c=Context({'current_date':str(now)})
html=t.render(c)
return HttpResponse(html)

 

另一种写法(推荐)
  import datetime
  now=datetime.datetime.now()
  return render(req, 'current_datetime.html', {'current_date':str(now)[:19]})


# 总结:咱们之前这么写
  render(request,'模板名字',context={key:value,key1:value})
  本质是:
  t=Template('<html><body>现在时刻是:<h1>{{current_date}}</h1></body></html>')
  c=Context({'current_date':str(now)})
  html=t.render(c) # 返回是字符串
  HttpResponse(html)

 

页面静态化#######
-把什么页面,做成静态化的?---》访问量高的页面
-目的:提高项目并发量,响应速度和效率就高了
-把首页静态化

def index(request):
# 1 判断 cache文件夹下有没有 index.html 纯静态页面
# 2 如果没有:干下面的事
# books = Book.object.all()
# t = Template('<html><body>现在时刻是:<h1>{{current_date}}</h1></body></html>')
# # #t=get_template('current_datetime.html')
# c = Context({'books':books})
# html = t.render(c)
#保存到某个文件中 cache文件夹下 index.html
# 3 如果有那个文件,打开文件---》HttpReponse
books=Book.object.all()
return render(request,'index.html',{books:books})

 

模板语法###
变量:{{ 变量名 }} 字典,列表,对象 通过.拿到属性或方法
字典:dic.name--->这不是python语法 dic['name'] dic.get('name')
列表:list.2--->这不是python语法 list[0]
对象:person.name---->是python语法
person.run---->不是python语法,会自动加括号,把run的返回值放在模板中 person.run()
不支持传参数

1 深度查询 用句点符
2 过滤器
3 标签:{{% % }}

 

 

内置过滤器####
# render(request,'index.html',{now:当前时间对象})
{{ now | date:"Y-m-d H:i:s" }}

safe 把标签字符串 渲染成标签
'<a href=""></a>'--->渲染成标签

dtl是不存在xss攻击的?跨站脚本攻击
# 后端:
s='
<script>
alert(1)
</script>
'
render(request,'index.html',{s:s})
#模板
{{s}} 不会渲染成标签,没有xss攻击
我们知道s是安全的,我们可以使用safe标签,把它渲染成 真正的标签

 

模板导入 include ,写好一段前端代码块,以后别的页面要用,直接 {% include 'little.html' %}
#### little.html 这个是以后要导入的代码块
<div>
  <h1>我是广告</h1>
  <p>亚洲最大同性交友平台</p>
  <p>名字是:{{ name }}---诚信交友</p>
</div>

#### 在index.html 或者 login.html中想用
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>

</head>
<body>

<div>
  {% include 'little.html' %} # 这个位置引入即可,但是如果little中有模板语法,需要如下
</div>
<hr>
<div>
  我是div222
</div>

</body>
</html>

### python代码:
def index(request):
return render(request, 'index.html', {'name': '彭于晏'})

-1 {{变量}} {{变量.取值}}
-2 {%for%}
-3 {%if%}
-5 内置过滤器 :data,length。。。
-6 include
-7 extends使用

————————————————————————————————————————————————————————————————————————————————————————————————

0 cbv执行流程,self问题(写代码试试) ---》整理到笔记中

cbv执行流程: 请求进入——进行路由匹配——如果匹配到对应的路由,内部就会执行XXXview.as_view()(request),因为XXXview中没有as_view()这个方法,所以去它的父类View中找,内部开始执行,View的as_view内部的view闭包函数,闭包函数执行了self.dispatch,这里的self是在XXXview类实例化的对象,在self.dispatch中通过反射找到同名的方法,然后执行,把request传入。

 



# 1 你自己写一个类,实现JsonResponse 功能,不需要传safe=False,无论字典或列表,都能完成序列化返回给前端

如果写在哪里都觉得不合适,那么新建一个py文件(名字随意) 在里面写一个 类   class MyResponse()那么他一定要继承一个类

要继承 HttpResponse,那么需要把这个 HttpResponse 导进来  (要从django中导过来)from django.shortcuts impor HttpResponse

注:肯定是不能继承 JsonResponse的  只用pass就行 ,所以我们要用 HttpResponse 逻辑重写    ——类加括号 会触发他的 __init__

但是你传了一个参数 就需要接收它 (简单的话 只需要判断它是不是列表参数或者字典参数,否则不能处理) 也可以

res=json dumps(data)  return super(  )_init_(res)            标红是绝对路径       去掉则是相对路径

而在视图函数中 views.py     def index(request)  导入之前写的  from(app01).response import MyResponse

({‘code’:100,‘msg:' 提交成功’})                                   

后 配路由    urls.py里                                                        

from app01.views import index   

urlpatterns =[

       path(‘admin/’),admin.site.urls},

       path(‘ ’,index),  根路径不要加 /

]              

 

   

 

 

 

# 2 四种情况,在响应头返回数据 xx=xx

四件套 导入  

 def index(request):

  return HttpResponse(‘ok’,headers=‘xxxx’)  前端可以看到的  ok   

  也可以   obj=HttpResponse(‘ok’)

  obj['???']='???'     像字典一样放入 最终会放到 Http的响应头中

  print obj     但是这是个对象  但两者效果是是一样的

插曲:

--------------------------------------------------------------------

  反向解析
# return redirect(‘ 第三方网址/自己的地址’)   

# res=resolve_url(' login')

   # return redirect(res)      通过名字拿到真正字符串地址——反向解析的作用    (在视图类,视图函数, 模板里)

---------------------------------------------------------------------------------------------------

————redirect  重定向

    def index(request)

    return redirect(‘ /login’,heraders={‘xxx’:‘xxxx’})   一访问 会重定向地址 需要往里放东西  而他的源代码里 有 **kwargs  参数

urls:  path(‘login/’,login,name=‘login’)

views  : def login (request):

  return HttpResponse(‘login’)  访问首页跳到页面  访问头  没有  说明不生效 ,这时 需要用到上面的OBJ

  obj=redirect=(‘/login’)

  obj['xxx']='xxx'

  return  obj       这时访问头 有数据

   

 

————render

   return render(request,‘ index.html’,headers={''xxx'='xxx') 

  建一个 html  不需要填写  直接跳转后  发现不能接受 hearders  只能再用 OBJ

    obj=render(request,‘index.html’)

    obj[xxx']='xxx'

    return  obj     此时可以访问   

————JsonResponse

    return JsonResponse({‘name’:‘sdsd’}),headers={‘xxx’:‘xxxxx’}   有提示  所以 当有提示的时候  此方法可行

    obj =JsonResponse({‘name’:‘xxxx’})

    obj=['xxx']='xxx'

    return obj   发现也可以访问    因此我们得出 obj四个都可以使用,而 headers方法 不具有通用性

# 3 绑定给类的方法,类来调用,对象可以调用吗?如何用
  绑定给对象的方法,对象来调用,类可以来调用吗?如何用

class Person:

# 对象绑定方法---》写在类中,没有任何装饰器
  def run(self):
     print(self.name)
     print('人走路')

类来调用对象的绑定方法---》这个方法就变成了普通函数,有几个值就要传几个值

正常需要传这个类的对象---》因为可能方法内部使用了对象
但是如果内部没有使用对象---》可以随意传个对象

Person.run(Person( ))   但是取name时 是因为 Person 对象没有 name属性     

      类可以来调  但是要把对象传进去 有几个传几个   

———— 类的绑定办法  必须要用 classmethon修饰

      @classmethond

      def xx(cls):     [括号内是形参,具体需要看调用传的是谁]  

      把类传入,类可以实例化得到对象  ——cls()   但是里面如果写了__init__   会报错    因为cls()=Person()

      p=cls() 直接类实例化得到对象 要不要传参数 取决于 Person类有没有写 _init_

      print(p) ------内存地址

print(‘ 类的绑定方法.xxx’)

 

绑定给类的方法
  Person.xx() 就是将自己本身传进去

p=Person()

p.xx()  对象来调用类的绑定方法实际是 将当前对象的类传递进去

 

类中还有 静态方法      [虽然叫静态方法  但是本质 是个函数]

  @staticmethod

  def yy():

    print(‘staticmethod’)

Person.yy()         [类来调用]

Person().yy() [对象来调用]    二者是不一样的  

总结:函数和方法

方法有特殊性,绑定给谁,就需要谁来调用,调用时会自动传值---》只能能自动传值,它就是个方法
# 函数,有几个值就要传几个值,不能多也不能少

 

# 5 写个图片上传功能,图片保存在根路径media文件夹下,上传成功直接在前端显示出上传的图片
-开启media的访问

创建一个media文件 

views:   def upload_ing(request):

       myfile=request.FILES.get(' myfile')

      with open("/media%s"%myfile.name,'wb' ) as f:

      for line in myfile:

        f.write(line)

   return HttpResponse('图片上传成功')     缺少前端form表单 写或者用postman  

urls: path(‘upload_imgg/’,upload_img),   启用路径 发POST请求

注掉 srf  后会发现 没有文件夹 的路径   

  可在 setting中   MEDIA_ROOT=os.path.join(BASE_DIR,'media')      而此时 需要修改views  导入路径

而  from.django.conf import setting  和from_dem04 import setting  二者 前者是系统内置  缺少的会内补   后者是自己配置 缺少会报错

print(settings.MEDIA_ROOT)  

 with open("/media%s"%myfile.name,'wb' ) as f: 改为 with open(settings.MEDIA_ROOT+'/%S' % myfile.name,'wb')as f:

 

访问不到的原因  是路径  需要将其开启  

而static文件夹 配置文件写好会自动开启   假如static文件里有个图片 ,不能直接 http://127.0.0.1:8000/static/img/default.png

配置文件没有配   

STATIC_URL =‘/static/’

STATICFILES_DIRS=[os.path.join(BASE_DIR,'static')]     注:static文件下不要放重要内容

想让media这个文件夹像static文件夹一样,能被用户浏览器访问---》自己开启路由-->url中写路由

from django.views.static imoprt serve

from django.conf import settings

访问的路径是:http://127.0.0.1:8000/ media/default.png
  -正则方法 re_path
  re_path('^media/(?P<path>.*)', serve, kwargs={'document_root': settings.MEDIA_ROOT}),
  media/   img/default.png
  访问meida这种路径,django会去 document_root指定的文件夹下找对应的文件
-转换器 path
  path('media/<path:path>', serve, kwargs={'document_root': settings.MEDIA_ROOT})

3 以后想开启media的访问
1 在项目根路径创建media文件
2 在配置文件中配置
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
3 路由中配置:path('media/<path:path>', serve, kwargs={'document_root': settings.MEDIA_ROOT})
'''
return HttpResponse('图片上传成功')

 


# 6 建个表---》插入100条数据---》写个页面,for循环把100条数据显示在页面上
-只要用户访问---》就会去查
-做成静态化

models.py   

form django.import models

class

  Book(models.Modexl):

  name=models.CharField(max_length=32)

  price =models.IntergerField()

  publish=models.CharField(max_length=64)

迁移数据库  ——Run manage.py Task       makemigration   megritae

from.models import Book           

 

from .models import Book
from django.conf import settings
from django.template import Template, Context

def books_view(request)   页面展示图书  先查看所有书

  做静态化

if os.path.exists(os.path.join(settings.BASE_DIR, 'cache', 'books.html')):
  print('不走数据库')
  with open('cache/books.html', 'rt', encoding='utf-8') as f:
    res_str = f.read()
  return HttpResponse(res_str)
else:
  books = Book.objects.all()
  with open('templates/books.html', 'rt', encoding='utf-8') as f:
    res = f.read()
  t = Template(res)
  c = Context({'books': books})
  html = t.render(c)
# 保存起来
with open('cache/books.html', 'wt', encoding='utf-8') as f:
    f.write(html)
return HttpResponse(html)

  

  

渲染模板   return  render(request,‘books.html’,{‘books’:book})

--books.html   

————bookstore      copy  div?》

 

 

 

 

 

 

 

 



# 7 (能做就做)自定义一个过滤器---》实现
数据有个表---》content字段---》别人存入了一些敏感词

它**

高级一些:关键词放到一个列表中,可以随时增加,不需要重启项目---》数据可以放在数据库中

 

posted @ 2023-11-29 20:45  拆尼斯、帕丁顿  阅读(13)  评论(0)    收藏  举报