环境准备
# 1. 开启一个新的项目 advanceDjango
(venv) E:\PythonLearn\djangoDemo>django-admin startproject advanceDjango # 2. 配置项目同名APP下的settings.py, advanceDjango/advanceDjango/settings.py ALLOWED_HOSTS = ['*'] TEMPLATES = [
'DIRS': [ os.path.join(BASE_DIR, 'templates') # 配置模板目录 ], # 配置数据库, 更换Sqlite3为MySQL DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'django_advance', 'HOST': '127.0.0.1', 'PORT': 3306, 'USER': 'dbman', 'PASSWORD': 'xxxxxx', 'CHARSET': 'utf8' } } # 3. 安装数据库驱动 pymysql, 默认是mysqlclient (venv) E:\PythonLearn\djangoDemo>pip install pymysql # 创建数据库django_advance mysql> create database django_advance default character set 'utf8'; Query OK, 1 row affected, 1 warning (0.01 sec) # 在 advanceDjango/advanceDjango/__init__.py 引入MySQL 初始化 import pymysql pymysql.install_as_MySQLdb()
一、 请求与响应之Request
1.1 Request对象
1.1.1 Request 请求对象类; 在视图函数的第一个参数上; 请求是由Django框架生成的
1.1.2 请求对象中的普通信息
- path: 请求路径
- method: 请求方法; GET/POST/PUT/DELETE
- content_type: 数据类型, 如请求头的Context-Type: text/html;charset=utf-8
- encoding: 编码方式, 如utf-8
- body: 字节码数据,一般接收上传的json数据
1.1.3 请求对象中的QueryDict属性, QueryDict自动进行url的中文编码处理
- GET: 查询参数, 包含get请求的所有参数
- POST: 表单参数, 包含post/put两个请求方法的参数;PUT上传的数据用body来获取
- COOKIES: 客户端中的当前domain的所有Cookie信息
- FILES: 上传的表单参数中所有的文件对象
- session: 会话中存储的数据(可以跨多个请求)
- META: 客户端的元信息(服务器环境信息、客户端请求信息) REMOTE_ADDR 客户端IP地址
- PATH_INFO REQUEST_METHOD QUERY_STRING CONTENT_TYPE
1.1.4 GET/POST 参数
- 类字典结构; key-value存储数据; key可以重复;
- 获取值: GET.get(),获取不到返回None; GET[key] 获取不到抛出异常;
- 获取所有值: GET.getlist("")
1.2 user应用测试
1.2.1 基础准备, 新增user应用
(venv) E:\PythonLearn\djangoDemo>cd advanceDjango (venv) E:\PythonLearn\djangoDemo\advanceDjango>django-admin startapp user
1.2.2 定义视图函数
def register(request, user_id=None):
return render(request, 'register.html', locals())
1.2.3 定义路由
# 定义总路由, 在settings.py 注册应用 path('user/', include('user.urls', namespace='user')),
# 定义子路由
app_name = 'user'
urlpatterns = [
path('register/', views.register, name='register1'),
path('register/<user_id>/', views.register, name='register2')
]
1.2.4 编写 templates/register.html
<p>
请求路径: {{ request.path }}
<br/>
请求URI: {{ request.get_raw_uri }}
<pre>
URL: 统一资源定位符, 资源的网络地址
URI: 统一资源标识符, 用于Restful规范中
</pre>
</p>
<p>
请求方法: {{ request.method }}
<br>
content_type: {{ request.content_type }}
<br>
encoding: {{ request.encoding }}
<br>
content_params: {{ request.content_params }}
</p>
1.2.5 访问结果
1.2.6 访问 http://127.0.0.1:8000/user/register/11a
[10/Apr/2023 22:41:48] "GET /user/register/11a HTTP/1.1" 301 0 [10/Apr/2023 22:41:48] "GET /user/register/11a/ HTTP/1.1" 200 924
1.3 GET请求参数
<p> <form method="get" enctype="application/x-www-form-urlencoded"> <input name="name" placeholder="请输入用户名"> <br> <input name="phone" placeholder="手机号"> <br> 爱好: {% for love in loves %} <input type="checkbox" {% if forloop.first or forloop.last %} # 默认选中第一项和 最后一项 checked {% endif %} name="love" value="{{ love }}">{{ love }} {% endfor %} <br> <button>提交</button> </form> </p> <p> GET请求的查询参数 <ul> {% for key, value in request.GET.items %} {% ifnotequal key 'love' %} <li>{{ key }}:{{ value }}</li> {% endifnotequal %} {% endfor %} <li> 爱好: {% for item in select_loves %} {{ item }}, {% endfor %} </li> </ul> </p>
def register(request, user_id=None): loves = ['H5', 'Python', 'Java', 'GO', 'Linux']
# 获取参数名相同(love)的多个参数值 select_loves = request.GET.getlist('love') return render(request, 'register2.html', locals())
访问 /user/register , 输入数据后,点击提交
1.4 POST请求参数
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt def register3(request, user_id=None): print(request.POST) print(request.body) return render(request, 'register3.html', locals())
<form method="post" enctype="application/x-www-form-urlencoded"> <input name="name" placeholder="请输入用户名" value="{{ name }}"> <br> <input name="phone" placeholder="手机号" value="{{ phone }}"> <br> <button>提交</button> </form> <p> POST请求的查询参数 <ul> {% for key, value in request.POST.items %} <li>{{ key }}:{{ value }}</li> {% endfor %} </ul> </p>
POST返回结果
<QueryDict: {'name': ['Tom'], 'phone': ['15566665555']}> b'name=Tom&phone=15566665555'
POST请求参数格式
# es6-form 格式化: key=value&key=value 格式化的字符串 fetch('', { method: 'POST', body: 'name=' + data.name+'&phone='+data.phone,
1.5 PUT请求参数
1.5.1 PUT请求传递json数据
<p> <button onclick="up_ajax()">ajax发起PUT请求</button> <script> function up_ajax() { data = { name: 'TangSan', phone: '15500008753', loves: ['数学', 'Python', 'Java', '语文', 'Linux'] }; var formdata = document.forms[0] formdata.append('name', data.name); formdata.append('phone', data.phone) fetch('', { method: 'PUT', body: JSON.stringify(data), headers: { 'Content-Type': 'application/json;charset=utf-8' } }).then(response => response.text()).then(html => { document.write(html) }); } </script> </p> <p> 请求方法: {{ request.method }} <br> PUT请求的参数(body): {{ request.body }} <br> content_type: {{ request.content_type }} <br> encoding: {{ request.encoding }} <br> </p>
1.5.2 PUT请求传输form表单数据
body: document.forms[0].serialize, headers: { {#'Content-Type': 'application/json;charset=utf-8'#} 'Content-Type': 'application/x-www-form-urlencoded' }
1.6 上传文件
<form method="post" enctype="multipart/form-data"> <input name="name" placeholder="用户名"><br> <input name="phone" placeholder="手机号"><br> <input type="file" name="img"><br> <button>提交</button><br> </form>
from django.core.files.uploadedfile import InMemoryUploadedFile @csrf_exempt def register4(request, user_id=None): print(request.method) print(request.POST) print(request.FILES) name = request.POST.get('name') phone = request.POST.get('phone') upload_file: InMemoryUploadedFile = request.FILES.get('img') if upload_file: print(upload_file.name) print(upload_file.content_type) print(upload_file.size) print(upload_file.charset) # print(request.body) if all(( upload_file.content_type.startswith('image/'), upload_file.size < 120 * 1024 )): print(request.META.get('REMOTE_ADDR')) file_name = name + os.path.splitext(upload_file.name)[-1] # images 目录必须存在, advanceDjango项目目录下 with open('images/' + file_name, 'wb') as f: for chunk in upload_file.chunks(): f.write(chunk) f.flush() return HttpResponse('上传文件成功') return HttpResponse('请上传小于120KB的图片') return render(request, 'register4.html', locals())
POST
<QueryDict: {'name': ['Jack'], 'phone': ['15566667777']}>
<MultiValueDict: {'img': [<InMemoryUploadedFile: Django目录结构.png (image/png)>]}>
Django目录结构.png
image/png
54811
None
当保存图片等文件时,目录不存在会报错
二、 请求与响应之Response
2.1 response对象
响应对象是视图函数返回的对象。需自行创建,可由render()/redirect()快速生成response响应对象。
常用的响应类: HttpResponse、 HttpResponseRedirect、 JsonResponse
常用属性与方法:
- content: 响应内容,必须是bytes类型的数据 charset: 编码格式
- status: 响应状态码(200, 3xx, 404, 5xx) content_type: MIME类型
- init(): 初始化内容 write(): 直接写出文本 flush(): 刷新缓冲区
增加响应头:
- 响应对象中存在着 _headers 私有的字典对象 HttpResponseBase类。
- 在Django中, response对象具有dict的特性。 response['Content-Type'] = value
2.2 返回JSON格式数据
def register5(request): # 返回字符串格式的文本 resp1 = HttpResponse(content='您好'.encode('utf-8'), status=200, content_type='text/html;charset=utf-8') # 返回图片 with open('images/Jack.png', 'rb') as f: png_data = f.read() resp2 = HttpResponse(content=png_data, content_type='image/png') resp2.setdefault('Content-Length', len(png_data)) # 返回Json格式的数据 json_data = {'name': 'Jackson', 'age': 20} resp3 = HttpResponse(content=json.dumps(json_data), content_type='application/json') # 使用JsonResponse返回Json数据 resp4 = JsonResponse(json_data) return resp4
返回图片