Django基础(四)(Django Foundation (IV))

Django基础(四)

虚拟环境

django路由层版本区别

视图函数的返回值

JsonResponse对象

接收文件数据

FBV与CBV(基于函数的视图、基于类的视图)

CBV源剖析(学习查看源码)

模板语法传值

作业讲解

虚拟环境

我们在实际开发工作中 针对不同的项目需要为其配备对应的解释器环境
	eg:
    项目1 
    	django2.2 pymysql3.3 requests1.1
    项目2 
    	django1.1
    项目3
    	flask
诸多项目在你的机器上如何无障碍的打开并运行
  方式1:把所有需要用到的模块全部下载下来 如果有相同模块不同版本每次都重新下载替换
  方式2:提前准备好多个解释器环境 针对不同的项目切换即可
 
# 创建虚拟环境 
	相当于在下载一个全新的解释器
# 识别虚拟环境
	文件目录中有一个venv文件夹
# 如何切换环境
	选择不用的解释器即可 全文不要再次勾选new enviroment...

django版本区别

# 路由层
django1.x与2.x、3.x有些区别
1.路由匹配的方法不一样
url()    支持正则				path() 第一个参数不支持正则
如果想要使用正则的话就要使用:
from django.urls import path,re_path

2.path方法提供了转换器功能
path('index/<int:id>/',index)
匹配对应位置的数据并且自动转换类型

# 有五种转换器可供选择
1.str:匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
2.int:匹配数字,包括0
3.slug:匹配字母、数字、下划线以及横杆组成的字符串
4.uuid:匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00
5.path:匹配任何非空字符串,包含了路径分隔符(/),不能用"?"
    
eg:
    path('login/<int:year>',views.login),
    path('login/<str:name>',views.login),
    path('login/<path:p>',views.article),
    
 高级示例:
实现匹配这种路径:http://127.0.0.1:8000/jason/p/4444.html
        path('<str:name>/p/<int:id>.html',views.article),
        re_path(r'^(?P<name>.*?)/p/(?P<id>\d+).html$',views.login)
        url(r'^(?Pname>.*?)/p/(?P<id>\d+).html$',views.login)
        url在2.x之后的版本不建议使用,可以使用re_path代替
        
 # 转化器不能在re_path中使用

视图函数返回值

# 视图函数必须返回一个HttpResonse对象
	HttpResponse
  	class HttpResponse(...):
      pass
  render
  	def render(...):
      return HttpResponse(...)
  redirect
  	def redirect(...):
      # 多继承

JsonResponse

user_dict = {'name': 'jason', 'pwd': 123, 'hobby': '好好学习'}
return JsonResponse(user_dict,json_dumps_params={'ensure_ascii':False})

class JsonResponse(HttpResponse):
	def __init__(self, data,json_dumps_params=None, **kwargs):
		data = json.dumps(data, **json_dumps_params)
  
"""为什么使用JsonResponse还不是原始的json模块"""
django对json序列化的数据类型的范围做了扩充	
	回忆之前我们自己扩展的序列化方法

form表单上传文件

form表单上传的数据中如果含有文件 那么需要做以下几件事
	1.method必须是post
  2.enctype必须修改为multipart/form-data
  	默认是application/x-www-form-urlencoded
  3.后端需要使用request.FILES获取
  	# django会根据数据类型的不同自动帮你封装到不同的方法中

request其他方法

request.method
request.POST
request.GET
request.FILES
request.body
	存放的是接收过来的最原始的二进制数据
  request.POST、request.GET、request.FILES这些获取数据的方法其实都从body中获取数据并解析存放的
request.path
	获取路径
request.path_info
	获取路径
request.get_full_path()
	获取路径并且还可以获取到路径后面携带的参数

FBV与CBV

FBV:基于函数的视图
  url(r'^index/',函数名)
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方法
 	"""

CBV源码剖析

1.切入点:路由匹配
  类名点属性as_view并且还加了括号
  	as_view可能是普通的静态方法
    as_view可能是绑定给类的方法
2.对象查找属性的顺序
	先从对象自身开始、再从产生对象的类、之后是各个父类
  	MyLoginView.as_view()
    	先从我们自己写的MyLoginView中查找
     	没有再去父类Views中查找
3.函数名加括号执行优先级最高
	url(r'^ab_cbv/', views.MyLoginView.as_view())
  项目已启动就会执行as_view方法 查看源码返回了一个闭包函数名view
  def as_view(cls):
    def view(cls):
      pass
    return view
  url(r'^ab_cbv/', views.view)
  # CBV与FBV在路由匹配本质是一样的!!!
4.路由匹配成功之后执行view函数
	def view():
    self = cls()
    return self.dispatch(request, *args, **kwargs)
5.执行dispatch方法
	需要注意查找的顺序!!!
  def dispatch():
      handler = getattr(self, request.method.lower())
      return handler(request, *args, **kwargs)
"""查看源码也可以修改 但是尽量不要这么做 很容易产生bug"""

模板语法传值

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


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

2.传值的范围
	基本数据类型都可以
  函数名
  	模板语法会自动加括号执行并将函数的返回值展示到页面上
    不支持传参(模板语法会自动忽略有参函数)
 	文件名
  	直接显示文件IO对象
  类名
  	自动加括号实例化成对象
  对象名
  	直接显示对象的地址 并且具备调用属性和方法的能力
  
# django模板语法针对容器类型的取值 只有一种方式>>>:句点符
	既可以点key也可以点索引  django内部自动识别
  	{{ data1.info.pro.3.msg }}

作业讲解

使用无名有名反向解析完成用户数据的编辑功能与删除功能

1.models.py文件

from django.db import models

# Create your models here.


class User(models.Model):
    name = models.CharField(max_length=32)
    pwd = models.IntegerField()

2.urls.py文件

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # 数据展示
    url(r'^$',views.home,name='home.view'),
    # 数据编辑
    url(r'^edit_data/(?P<edit_id>\d+)/',views.edit_data,name='edit_view')
    # 数据删除
    url(r'^delete_data/(?P<delete_id>\d+)/',views.delete_data,name='delete_view')
]

3.views,py文件

from django.shortcuts import render,HttpResponse,redirect
from app01 import models
# Create your views here.

def home(request):
    data_queryset = models.User.objects.filter()    # 列表套对象[obj1,obj2]
    return render(request,'home.html',{'data_list':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')
        # 修改原数据(方式一)
        #models.User.objects.filter(id=edit_id).update(name=username,pwd=password)
        # 修改原数据(方式二)
        edit_obj.name = username
        edit_obj.name = 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')

4.home.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
bootstrap/3.4.1/js/bootstrap.min.js"></script>#}
</head>
<body>
<div class="container">
    <div class="row">
        <h1 class="text-center">数据展示</h1>
        <div class="col-md-8 col-md-offset-2">
            <table class="table table-hover table-striped">
                <thead>
                    <tr>
                        <th>主键</th>
                        <th>姓名</th>
                        <th>密码</th>
                        <th class="text-center">操作</th>
                    </tr>
                </thead>
                <tbody>
                    {% for data_obj in data_list %}
                        <tr>
                            <td>{{ data_obj.id }}</td>
                            <td>{{ data_obj.name}}</td>
                            <td>{{ data_obj.pwd }}</td>
                            <td class="text-center">
                                <a href="{% url 'edit_view' data_obj.id %}" class="btn btn-primary btn-xs">编辑</a>
                                <a href="{% url 'edit_view' data_obj.id %}" class="btn btn-danger btn-xs">删除</a>
                            </td>
                        </tr>
                    {% endfor %}

                </tbody>
            </table>

        </div>
    </div>
</div>
</body>
</html>

5.edit.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
bootstrap/3.4.1/js/bootstrap.min.js"></script>#}
</head>
<body>
    <div class="container">
        <div class="row">
            <h1 class="text-center">数据编辑</h1>
            <div class="col-md-8 col-md-offset-2">
                <from action="" method="post">
                    <p>username:
                        <input type="text" name="username" class="form-control" value="{{ edit_obj.name }}">
                    </p>
                    <p>password:
                        <input type="text" name="password" class="form-control" value="{{ edit_obj.pwd }}">
                    </p>
                    <input type="text" class="btn btn-succes bth-block" value="编辑数据">
                </from>
            </div>
        </div>
    </div>
</body>
</html>
————————

Django基础(四)

virtual environment

Differences between Django routing layer versions

Return value of view function

JsonResponse对象

Receive file data

FBV and CBV (function based view, class based view)

CBV source analysis (learn to view the source code)

Template syntax value transfer

Homework explanation

virtual environment

我们在实际开发工作中 针对不同的项目需要为其配备对应的解释器环境
	eg:
    项目1 
    	django2.2 pymysql3.3 requests1.1
    项目2 
    	django1.1
    项目3
    	flask
诸多项目在你的机器上如何无障碍的打开并运行
  方式1:把所有需要用到的模块全部下载下来 如果有相同模块不同版本每次都重新下载替换
  方式2:提前准备好多个解释器环境 针对不同的项目切换即可
 
# 创建虚拟环境 
	相当于在下载一个全新的解释器
# 识别虚拟环境
	文件目录中有一个venv文件夹
# 如何切换环境
	选择不用的解释器即可 全文不要再次勾选new enviroment...

django版本区别

# 路由层
django1.x与2.x、3.x有些区别
1.路由匹配的方法不一样
url()    支持正则				path() 第一个参数不支持正则
如果想要使用正则的话就要使用:
from django.urls import path,re_path

2.path方法提供了转换器功能
path('index/<int:id>/',index)
匹配对应位置的数据并且自动转换类型

# 有五种转换器可供选择
1.str:匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
2.int:匹配数字,包括0
3.slug:匹配字母、数字、下划线以及横杆组成的字符串
4.uuid:匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00
5.path:匹配任何非空字符串,包含了路径分隔符(/),不能用"?"
    
eg:
    path('login/<int:year>',views.login),
    path('login/<str:name>',views.login),
    path('login/<path:p>',views.article),
    
 高级示例:
实现匹配这种路径:http://127.0.0.1:8000/jason/p/4444.html
        path('<str:name>/p/<int:id>.html',views.article),
        re_path(r'^(?P<name>.*?)/p/(?P<id>\d+).html$',views.login)
        url(r'^(?Pname>.*?)/p/(?P<id>\d+).html$',views.login)
        url在2.x之后的版本不建议使用,可以使用re_path代替
        
 # 转化器不能在re_path中使用

View function return value

# 视图函数必须返回一个HttpResonse对象
	HttpResponse
  	class HttpResponse(...):
      pass
  render
  	def render(...):
      return HttpResponse(...)
  redirect
  	def redirect(...):
      # 多继承

JsonResponse

user_dict = {'name': 'jason', 'pwd': 123, 'hobby': '好好学习'}
return JsonResponse(user_dict,json_dumps_params={'ensure_ascii':False})

class JsonResponse(HttpResponse):
	def __init__(self, data,json_dumps_params=None, **kwargs):
		data = json.dumps(data, **json_dumps_params)
  
"""为什么使用JsonResponse还不是原始的json模块"""
django对json序列化的数据类型的范围做了扩充	
	回忆之前我们自己扩展的序列化方法

Form upload file

form表单上传的数据中如果含有文件 那么需要做以下几件事
	1.method必须是post
  2.enctype必须修改为multipart/form-data
  	默认是application/x-www-form-urlencoded
  3.后端需要使用request.FILES获取
  	# django会根据数据类型的不同自动帮你封装到不同的方法中

request其他方法

request.method
request.POST
request.GET
request.FILES
request.body
	存放的是接收过来的最原始的二进制数据
  request.POST、request.GET、request.FILES这些获取数据的方法其实都从body中获取数据并解析存放的
request.path
	获取路径
request.path_info
	获取路径
request.get_full_path()
	获取路径并且还可以获取到路径后面携带的参数

FBV与CBV

FBV:基于函数的视图
  url(r'^index/',函数名)
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方法
 	"""

CBV source code analysis

1.切入点:路由匹配
  类名点属性as_view并且还加了括号
  	as_view可能是普通的静态方法
    as_view可能是绑定给类的方法
2.对象查找属性的顺序
	先从对象自身开始、再从产生对象的类、之后是各个父类
  	MyLoginView.as_view()
    	先从我们自己写的MyLoginView中查找
     	没有再去父类Views中查找
3.函数名加括号执行优先级最高
	url(r'^ab_cbv/', views.MyLoginView.as_view())
  项目已启动就会执行as_view方法 查看源码返回了一个闭包函数名view
  def as_view(cls):
    def view(cls):
      pass
    return view
  url(r'^ab_cbv/', views.view)
  # CBV与FBV在路由匹配本质是一样的!!!
4.路由匹配成功之后执行view函数
	def view():
    self = cls()
    return self.dispatch(request, *args, **kwargs)
5.执行dispatch方法
	需要注意查找的顺序!!!
  def dispatch():
      handler = getattr(self, request.method.lower())
      return handler(request, *args, **kwargs)
"""查看源码也可以修改 但是尽量不要这么做 很容易产生bug"""

Template syntax value transfer

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


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

2.传值的范围
	基本数据类型都可以
  函数名
  	模板语法会自动加括号执行并将函数的返回值展示到页面上
    不支持传参(模板语法会自动忽略有参函数)
 	文件名
  	直接显示文件IO对象
  类名
  	自动加括号实例化成对象
  对象名
  	直接显示对象的地址 并且具备调用属性和方法的能力
  
# django模板语法针对容器类型的取值 只有一种方式>>>:句点符
	既可以点key也可以点索引  django内部自动识别
  	{{ data1.info.pro.3.msg }}

Homework explanation

Use anonymous name reverse parsing to complete the editing and deletion of user data

1.models. Py file

from django.db import models

# Create your models here.


class User(models.Model):
    name = models.CharField(max_length=32)
    pwd = models.IntegerField()

2.urls. Py file

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # 数据展示
    url(r'^$',views.home,name='home.view'),
    # 数据编辑
    url(r'^edit_data/(?P<edit_id>\d+)/',views.edit_data,name='edit_view')
    # 数据删除
    url(r'^delete_data/(?P<delete_id>\d+)/',views.delete_data,name='delete_view')
]

3. Views, py file

from django.shortcuts import render,HttpResponse,redirect
from app01 import models
# Create your views here.

def home(request):
    data_queryset = models.User.objects.filter()    # 列表套对象[obj1,obj2]
    return render(request,'home.html',{'data_list':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')
        # 修改原数据(方式一)
        #models.User.objects.filter(id=edit_id).update(name=username,pwd=password)
        # 修改原数据(方式二)
        edit_obj.name = username
        edit_obj.name = 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')

4.home. HTML file

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
bootstrap/3.4.1/js/bootstrap.min.js"></script>#}
</head>
<body>
<div class="container">
    <div class="row">
        <h1 class="text-center">数据展示</h1>
        <div class="col-md-8 col-md-offset-2">
            <table class="table table-hover table-striped">
                <thead>
                    <tr>
                        <th>主键</th>
                        <th>姓名</th>
                        <th>密码</th>
                        <th class="text-center">操作</th>
                    </tr>
                </thead>
                <tbody>
                    {% for data_obj in data_list %}
                        <tr>
                            <td>{{ data_obj.id }}</td>
                            <td>{{ data_obj.name}}</td>
                            <td>{{ data_obj.pwd }}</td>
                            <td class="text-center">
                                <a href="{% url 'edit_view' data_obj.id %}" class="btn btn-primary btn-xs">编辑</a>
                                <a href="{% url 'edit_view' data_obj.id %}" class="btn btn-danger btn-xs">删除</a>
                            </td>
                        </tr>
                    {% endfor %}

                </tbody>
            </table>

        </div>
    </div>
</div>
</body>
</html>

5.edit. HTML file

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
bootstrap/3.4.1/js/bootstrap.min.js"></script>#}
</head>
<body>
    <div class="container">
        <div class="row">
            <h1 class="text-center">数据编辑</h1>
            <div class="col-md-8 col-md-offset-2">
                <from action="" method="post">
                    <p>username:
                        <input type="text" name="username" class="form-control" value="{{ edit_obj.name }}">
                    </p>
                    <p>password:
                        <input type="text" name="password" class="form-control" value="{{ edit_obj.pwd }}">
                    </p>
                    <input type="text" class="btn btn-succes bth-block" value="编辑数据">
                </from>
            </div>
        </div>
    </div>
</body>
</html>