Django基础篇:虚拟环境、路由层版本区别、视图函数返回值、JsonResponse对象、from表单、request其他方法、FBV与CBV、模板语法

2022.5.13 diango虚拟环境、路由层版本区别、视图层基础操作

  • 虚拟环境
  • django路由层版本区别
  • 视图函数返回值
  • JsonResponse对象
  • django接收form表单上传文件
  • request其他方法
  • FBV与CBV
  • CBV源码剖析
  • 模板语法传值

一、虚拟环境

在实际开发工作中,针对不同的项目需要为其配备对应的解释器环境>>>:

eg:
    项目1 
    	django2.2 pymysql3.3 requests1.1
    项目2 
    	django1.1
    项目3
    	flask
问:如何让诸多项目使用不同环境并且无障碍地打开运行?
	方式1:下载所有模块,如果有相同模块不同版本每次都重新下载替换  >>>  不合理
    方式2:提前准备好多个解释器环境,针对不同的项目切换即可  >>>  虚拟环境
    
# 创建虚拟环境
	相当于在下载一个全新的解释器
    new project
    	pure python	
        	new environment using
            	选择解释器版本
                	不勾选 Inherit global site-packages(继承本地解释器环境)
                    勾选 Make avaiable to all projects(让所有项目使用该环境)
                    	create
# 识别虚拟环境
	文件目录中有一个venv文件夹
# 如何切换环境
	选择不同的解释器即可,全文不要再次勾选new environment using

二、django路由层版本区别

# django1.x 与 2.x、3.x有些许区别
	1.路由匹配方法不一样
        1.x      >>>   url()     支持正则
        2.x/3.x  >>>   path()    不支持正则
                如果想使用正则,也提供了方法:
                from dnango.urls import path,re_path
                re_path()  # 方法与url完全一致
	2.path方法提供了转换器功能 
    	path('index/<int:id>/', index)
        <>  # 匹配对应位置的数据并自动转换类型,共五种转换类型

# 五种转换类型
    str:匹配任何非空字符串,但不含斜杠/,如果你没有专门指定转换器,那么这个是默认使用的;
    int:匹配0和正整数,返回一个int类型
    slug:可理解为注释、后缀、附属等概念,是url拖在最后的一部分解释性字符。该转换器匹配任何ASCII字符以及连接符和下划线,比如“ building-your-1st-django-site”;
    uuid:匹配一个uuid格式的对象。为了防止冲突,规定必须使用破折号,所有字母必须小写,例如’075194d3-6885-417e-a8a8-6c931e272f00‘ 。返回一个UUID对象;
    path:匹配任何非空字符串,重点是可以包含路径分隔符“/”。这个转换器可以帮助你匹配整个url而不是一段一段的url字符串 

三、视图函数返回值

在django框架中,调用视图函数必须有返回值,且必须返回一个HttpResponse对象;

在视图层中,HttpResponse、render、redirect,这三个都是返回HttpResponse对象;

HttpResponse

class HttpResponse(HttpResponseBase):
    streaming = False

render

def render(request, template_name, context=None, content_type=None, status=None, using=None):
    content = loader.render_to_string(template_name, context, request, using=using)
    return HttpResponse(content, content_type, status)

redirect

def redirect(to, *args, **kwargs):
    if kwargs.pop('permanent', False):
        redirect_class = HttpResponsePermanentRedirect
    else:
        redirect_class = HttpResponseRedirect
    return redirect_class(resolve_url(to, *args, **kwargs))

# 查看源码得知,redirect通过层层嵌套也是间接继承和返回了HttpResponse

总结:视图层自定义函数必须返回带有HttpResponse对象的返回值

四、JsonResponse对象

django中的JsonResponse模块相当于对json序列化的数据类型的范围做了扩充,查看源码,其实还是使用的原始的json模块;

# JsonResponse源码
class JsonResponse(HttpResponse):
    def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
                 json_dumps_params=None, **kwargs):
        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('content_type', 'application/json')
        data = json.dumps(data, cls=encoder, **json_dumps_params)  # 还是使用json方法
        super(JsonResponse, self).__init__(content=data, **kwargs)

代码验证

from django.http import JsonResponse


def ab_json(request):
    1.HttpResponse传递字典  >>>  无法json序列化
    user_dict = {"name":'jason','pwd':123,'hobby':'好好学习'}
    dict_json = json.dumps(user_dict,ensure_ascii=False)
    return HttpResponse(dict_json)
	2.JsonResponse传递字典
    
    user_dict = {'name': 'jason', 'pwd': 123, 'hobby': '好好学习'}
    return JsonResponse(user_dict,json_dumps_params={'ensure_ascii':False})  # 为防止乱码,需要设置json_dumps_params

	3.JsonResponse传递列表
    user_list = [11, 22, 33, 44, 55]
    return JsonResponse(user_list, safe=False)  # 为防止乱码,需要设置safe=False

五、django接收form表单上传文件

form表单上传的数据中如果含有文件,那么需要做以下几件事:

1.method必须是post

<form action="" method="post" enctype="multipart/form-data">

2.enctype必须修改为multipart/form-data(默认是application/x-www-form-urlencoded)

<form action="" method="post" enctype="multipart/form-data">
    <p>username:
    	<input type="text" name="username" class="form-control">
    </p>
    <p>files:
        <input type="file" name="my_file" class="form-control" multiple>
    </p>
        <input type="submit" class="btn btn-success btn-block">
</form>

3.后端需要使用request.FILES获取

def ab_form(request):
    if request.method == 'POST':
        print(request.POST)  # 不能获取文件数据
        print(request.FILES)  # 专门获取文件数据
        file_obj = request.FILES.get('my_file')  # 'my_file'是input的name值
        print(file_obj.name)  # 查看文件名
        with open(file_obj.name,'wb') as f:
            for line in file_obj:  # 相当于粘贴文件到当前文件夹
                f.write(line)

六、request其他方法

request.method
request.POST
request.GET
request.FILES
request.body  # 存放的是接收过来的最原始的二进制数据
	
ps:request.POST、request.GET、request.FILES这些获取数据的方法其实都从body中获取数据并解析存放的;

request.path
	获取路径即url
request.path_info
	获取路径即url
request.get_full_path()
	获取路径(url)并且还可以获取到路径(?...)后面携带的参数

七、FBV与CBV

1、FBV

基于函数的视图

2、CBV

基于类的视图

# 视图层
from django import views
class MyLoginView(views.View):
    def get(self, request):
        return HttpResponse("from CBV get view")
    def post(self, request):
        return HttpResponse("from CBV post view")
# 路由层
url(r'^ab_cbv/', views.MyLoginView.as_view())
 	"""
 	如果请求方式是GET,则会自动执行类里面的get方法;
 	如果请求方式是POST,则会自动执行类里面的post方法;
 	"""

3、CBV源码剖析

(1)路由层创建关系

url(r'^ab_cbv/', views.MyLoginView.as_view())  # MyLoginView是即将要创建的类名

分析:
	as_view可以是普通的静态方法;
    as_view可以是绑定给类的方法;
    项目启动后,访问此路由,由于函数加括号调用优先级最高,会先执行as_view(),可以看成一个返回值;

(2)在视图层创建类

class MyLoginView(views.View):
    def get(self, request):
        return HttpResponse("from CBV get view")
    def post(self, request):
        return HttpResponse("from CBV post view")
    
# 使用get请求后,结果为:from CBV get view
# 使用post请求后,结果为:from CBV post view

分析:
	类MyLoginView并没有相关方法能够识别get和post请求,那么必定在继承的父类中,我们接下来查看View源码

(3)查看View源码

class View(object):
	# 1、请求方式
    http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']  # 共八种
	# 2.as_view函数
	@classonlymethod
    def as_view(cls, **initkwargs):
        ...  # 跳过部分代码
        def view(request, *args, **kwargs):
            ...  # 跳过部分代码
            return self.dispatch(request, *args, **kwargs)
        return view
    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)
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)
 
分析:
	运行步骤:
    (1)url调用views.MyLoginView.as_view(),先执行as_view; 
    (2)as_view()的返回值为view,因此:
        	views.MyLoginView.as_view() == views.MyLoginView.view;
    (3)路由匹配成功后执行view,执行类的dispatch方法(self.dispatch())
    (4)执行dispatch,判断如果请求方式在八种方式中,获取该请求方式的对应字符(handler)后,并加括号运行该函数:return handler()
    	因此:
    	as_view() == view;
        view() == dispatch() == handler();
    总结:
    	views.MyLoginView.as_view() == handler(request, *args, **kwargs)  # handler相当于不同的请求方式 >>> post,get...

八、模板语法传值

"""
django提供的模板语法只有两个符号
	{{}}:主要用于变量相关操作(引用)
	{%%}:主要用于逻辑相关操作(循环、判断)
"""

1.传值的两种方式
	# 传值方式1:指名道姓的传,适用于数据量较少的情况,节省资源
    return render(request, 'ab.html', {'name':name})
	# 传值方式2:打包传值,适用于数据量较多的情况(偷懒),浪费资源
      '''locals() 将当前名称空间中所有的名字全部传递给html页面'''
    return render(request, 'ab_temp.html', locals())

2.传值的范围
	基本数据类型都可以;
    函数名:
        模板语法会自动加括号执行并将函数的返回值展示到页面上;
        不支持传参(模板语法会自动忽略有参函数);
    文件名:
  		直接显示文件IO对象;
    类名:
  		自动加括号实例化成对象;
    对象名:
  		直接显示对象的地址,并且具备调用属性和方法的能力;

# django模板语法针对容器类型的取值 只有一种方式>>>:句点符
	data1 = {'info':{'pro':[11, 22, 33, {'name':'jason','msg':'努力就有收获'}]}};
	既可以点key值也可以点索引,django内部会自动识别;
  	{{ data1.info.pro.3.msg }}

昨日作业

1.数据展示
2.给按钮附加功能
3.如何明确用户到底想要编辑哪条数据
	在路由匹配中就应该获取到用户想要编辑的数据主键值
4.点击编辑按钮 应该展示当前数据的编辑页面
	通过无名或者有名分组获取到用户想要编辑的数据主键值
  获取对应的数据对象传递给页面 展示给用户看并提供编辑功能
5.编写删除功能
	路由设计跟编辑功能一致

def home(request):
    data_queryset = models.User.objects.filter()  # [obj1,obj2,obj3]
    return render(request,'home.html',{'data_queryset':data_queryset})


def edit_data(request,edit_id):
    # 获取用户编辑的数据对象
    edit_obj = models.User.objects.filter(id=edit_id).first()
    if not edit_obj:
        return HttpResponse('当前用户编号不存在')
    if request.method == 'POST':
        # 获取新的数据
        username = request.POST.get('username')
        password = request.POST.get('password')
        # 修改原数据 方式1
        # models.User.objects.filter(id=edit_id).update(name=username,pwd=password)
        # 修改原数据 方式2
        edit_obj.name = username
        edit_obj.pwd = password
        edit_obj.save()
        # 重定向到展示页
        return redirect('home_view')  # 括号内也可以直接写反向解析的别名 不适用于无名有名反向解析
    # 将待编辑的数据对象传递给页面展示给用户看
    return render(request,'edit.html',{'edit_obj':edit_obj})


def delete_data(request,delete_id):
    # 获取想要删除的对象数据
    edit_queryset = models.User.objects.filter(id=delete_id)
    if not edit_queryset:
        return HttpResponse("用户编号不存在")
    edit_queryset.delete()
    return redirect('home_view')
posted @ 2022-05-13 22:37  马氵寿  阅读(89)  评论(0)    收藏  举报