GVKun编程网logo

Django 系列博客(二)(django blog)

8

最近很多小伙伴都在问Django系列博客和二这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展Django系列博客(一)、Django系列博客(七)、Django系列博客(三)、Dj

最近很多小伙伴都在问Django 系列博客这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展Django 系列博客(一)、Django 系列博客(七)、Django 系列博客(三)、Django 系列博客(九)等相关知识,下面开始了哦!

本文目录一览:

Django 系列博客(二)(django blog)

Django 系列博客(二)(django blog)

<h1 id="django-系列博客二">Django 系列博客(二)
<h2 id="前言">前言

今天博客的内容为使用 Django 完成第一个 Django 页面,并进行一些简单页面的搭建和转跳。

在上一篇博客中已经安装好了虚拟环境,所以用虚拟环境来安装指定版本的 Django。为了可以从头到尾的走一遍流程,我重新创建了一个虚拟环境。

  1. 首先进入虚拟环境路径下的 bin 目录
  2. 使用命令激活虚拟环境

  1. 安装指定版本 Django

首先使用 pip3 list 命令查看

可以看到都是创建虚拟环境时安装的依赖包,现在使用 pip 命令安装指定 django 版本,因为做项目需要稳定,所以安装的版本不是最新的。

可以看到新安装了2个包,pytz 是 python time zone 的缩写,是用来转换时区的包。

前往目标路径创建项目,在这里我的 django 项目都在我的家目录下面的 django_project里面。

进入要创建项目的路径下,使用下面的命令创建一个 django 项目。

django-admin startproject project_name

可以看到多了个文件夹。查看项目结构

进入项目根目录使用下面命令创建一个 app。

python3 manage.py startapp app_name

创建成功并查看项目结构。

使用下面命令

python3 manage.py runserver 127.0.0.1:8888

成功后会在本机上的8888端口开启 django 服务

访问8888端口会显示下图页面

好了,到现在你已经开启了第一个 django 服务,并且还是使用了命令行。

其实会使用命令行创建项目那么使用 pycharm 应该是手到擒来,毕竟 pycharm 已经做了很多工作了。不过也有点麻烦。。。

项目目录:包含项目最基本的一些配置
    -- __init__.py:模块的配置文件,将blog_proj文件夹变成了模块
    -- settings.py:配置总文件
    -- urls.py:url配置文件,django项目中的所有页面都需要对其配置URL地址
    -- wsgi.py:(web server gateway interface),服务器网关接口,python应用与web服务器直接通信的接口
templates:模板文件夹,存放html文件的(页面),支持使用Django模板语言(DTL),也可以使用第三方(jinja2)
manage.py:项目管理器,与项目交互的命令行工具集的入口,查看支持的所有命令python3 manage.py

import os # 项目根目录 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

项目安全码

SECRET_KEY = 'guwba1u$18=&*8kf44_u&swqb@xlwgel7n$0rs=(+f10yvz)p0'

调试模式,上线项目要关闭debug模式,不然后台出现异常会直接抛给前台展现给用户看了

DEBUG = True

在上线项目中,规定只能以什么ip地址来访问django项目

DEBUG = FALSE

ALLOWED_HOSTS = ['localhost']

ALLOWED_HOSTS = []

项目自带的应用

我们创建了自己的应用就要将自定义应用添加到该配置

INSTALLED_APPS = [
'django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles',]

中间件

django自带的工具集

MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware','django.contrib.sessions.middleware.SessionMiddleware','django.middleware.common.CommonMiddleware','django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware',]

配置url配件文件的根文件,执行urls.py

ROOT_URLconf = '项目目录.urls'

模板,一个个html文件

TEMPLATES = [
{

如果使用第三方,可以在这个地方修改模板引擎

    'BACKEND': 'django.template.backends.django.DjangoTemplates','D<a href="https://www.jb51.cc/tag/irs/" target="_blank">irs</a>': [<a href="https://www.jb51.cc/tag/ospath/" target="_blank">os.path</a>.join(BASE_DIR,'templates')],'APP_D<a href="https://www.jb51.cc/tag/irs/" target="_blank">irs</a>': True,'OPTIONS': {
        'context_processors': [
            'django.template.context_processors.debug','django.template.context_processors.request','django.contrib.auth.context_processors.auth','django.contrib.messages.context_processors.messages',],},]

服务器网关接口应用

Wsgi_APPLICATION = '项目目录.wsgi.application'

数据库配置

要配置自定义数据库去下面链接去查询详细配置

https://docs.djangoproject.com/en/1.11/ref/settings/#databases

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3','NAME': os.path.join(BASE_DIR,'db.sqlite3'),}
}

密码认证配置

https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',]

国际化相关配置

https://docs.djangoproject.com/en/1.11/topics/i18n/

LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True

静态文件地址 (CSS,JavaScript,Images)

https://docs.djangoproject.com/en/1.11/howto/static-files/

STATIC_URL = '/static/'


<h3 id="创建项目应用">创建项目应用

使用 pycharm 自带的命令行工具来创建应用

应用创建完后将应用名添加到 settings.py文件中

INSTALLED_APPS = [ 'django.contrib.admin',... 'django.contrib.staticfiles',# 添加的自定义应用 'app',]

创建后的 app 目录结构和使用命令行创建的一样,下面来看看具体都有什么作用

migrations:数据迁移(移植)模块,内容都是由Django自动生成
    -- __init__.py
__init__.py
admin.py:应用的后台管理系统配置
apps.py:django 1.9后,本应用的相关配置
models.py:数据模型模块,使用ORM框架,类似于MVC模式下的Model层
tests.py:自动化测试模块,可以写自动化测试脚本
views.py:执行相应的逻辑代码模块(相应什么,如何相应),代码逻辑处理的主要地点,项目的大部分代码所在位置

页面响应

一个响应

通过配置路由和视图文件来响应第一次连接请求。

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

导入应用视图

import app.views as app_view # 取别名

配置路由

urlpatterns = [
url(r'^admin/',admin.site.urls),# 为指定函数配置 url
url(r'^index/&',app_view.index)
]


<h4 id="配置视图">配置视图


<pre># 导入处理请求的 http 相应功能
from django.http import HttpResponse

django中每一个请求都会设置相应函数来进行处理

函数的参数约定为 request

def index(request):
return HttpResponse('index page!')

<h4 id="启动服务">启动服务

启动服务后访问 localhost:8000/index/,可以看到响应为 index 函数里填写的响应,说明服务成功启动并且响应了自己想要的响应字符串。

页面">第一个模板页面

项目目录下有个 templates 文件夹是专门用于存放页面资源的,比如index.html

from django.shortcuts import render

def index(request):

参数:请求对象 request,模板 html 文件,传给前台的资源

return render(request,'index.html')</code></pre>

index.html 文件

<Meta charset="UTF-8"> 主页

这是主页

配置完成后,访问127.0.0.1:8000/index/后显示为:

在 views.py文件中编写对应响应功能函数时,会自动出现模板文件

这是因为在 settings.py文件中已经把模板路径配置好了

TEMPLATES = [ { # 如果使用第三方,可以在这个地方修改模板引擎 'BACKEND': 'django.template.backends.django.DjangoTemplates',# 模板页面默认路径:项目根路径下的templates文件夹 'Dirs': [os.path.join(BASE_DIR,# 允许所有app均拥有自己的模板文件夹 'APP_Dirs': True,... },]

重定向">第一个重定向

和上面的一样,首先在 views.py文件中配置响应函数

from django.shortcuts import render,redirect # / 路径渲染index.html页面 def home(request): return render(request,'index.html') # /index/ 路径重定向到 / 路径,达到渲染index.html页面 def index(request): return redirect('/')

响应的路由配置为

from django.conf.urls import url from django.contrib import admin # 导入应用视图 import app.views as app_view urlpatterns = [ url(r'^admin/',url(r'^index/$',app_view.index),url(r'^$',app_view.home),]

状态码显示为301说明发生了转跳,查看网络详细信息发现在index/中有个 location 字段,

该字段值为 /,说明转跳到了根目录下。

文件

# 导入include功能,将url配置转移到指定应用内部的自身url配置文件 from django.conf.urls import url,include from django.contrib import admin urlpatterns = [ url(r'^admin/',# 将url配置操作交给app_test自身的urls.py来进行操作 # app-test/为app_test应用的总路径 url(r'^app-test/',include('app_test.urls')),]

文件

from django.conf.urls import url from . import views urlpatterns = [ # 1.不要直接留空,直接留空 http://localhost:8000/app-test/* 均可以访问 # 2.如果要配置index,访问的地址为 http://localhost:8000/app-test/index # 3.配置方式:r'^index/$',不要省略 / 符号 # 4.正则是否以$标识结尾取决于该路径是否会有下一级路径 url(r'^$',views.index),]

页面冲突

如果在两个应用中均有相同的模板页面假如为index.html

# 1.在应用templates文件夹下建立与应用同名的文件夹,eg:app_text下就建立app_text # 2.将模板创建在与应用同名的模板文件夹下 # 3.修改指定应用下views.py处理请求的render模板指向 def index(request): # 模板指向:blog_app应用的templates下的blog_app文件夹中的index.html return render(request,'app_text/index.html')

假如页面需要一些静态资源,比如需要 css 样式、js 文件等,那么就需要在 settings 文件中配置好静态文件的路径。

文件

# 静态文件地址 (CSS,Images) # https://docs.djangoproject.com/en/1.11/howto/static-files/ STATIC_URL = '/static/' # 在项目根目录下新建static文件夹,静态资源均放在该文件夹中 # 增加STATICFILES_Dirs配置 STATICFILES_Dirs = [ os.path.join(BASE_DIR,'static') ] # 前端页面加载静态资源的路径:/static/... (...为具体在static文件夹中的路径)

# 如果要将项目根目录下source文件夹也作为静态资源路径 # STATICFILES_Dirs增加source配置 STATICFILES_Dirs = [ os.path.join(BASE_DIR,'static'),os.path.join(BASE_DIR,'source') ] # 前端页面加载静态资源路径依旧不变,Django会自动索引:/static/... (...为具体在source文件夹中的路径)

# urls.py配置路由 url(r'test',app_view.test)

views.py设置响应函数

def test(request):
return HttpResponse('test')

问题:请求地址包含test均可以访问

http://127.0.0.1:8000/test => /test | /atest | /testa | /atesta | /test/a | /test/

<h3 id="开头">开头
<pre># urls.py配置路由
url(r'^test',app_view.test)

views.py设置响应函数

def test(request):
return HttpResponse('test')

问题:请求地址以test开头均可以访问

http://127.0.0.1:8000/test => /test | /testa | /test/a | /test/

<h3 id="结尾">结尾
<pre># urls.py配置路由
url(r'^test$',app_view.test)

views.py设置响应函数

def test(request):
return HttpResponse('test')

问题:只能一种方式访问

http://127.0.0.1:8000/test => /test

不能以 /test/ 访问

http://127.0.0.1:8000/test/

<h3 id="优化结尾">优化结尾
<pre># urls.py配置路由
url(r'^test/$',app_view.test)

views.py设置响应函数

def test(request):
return HttpResponse('test')

/test 和 /test/ 均可以访问

http://127.0.0.1:8000/test

http://127.0.0.1:8000/test/

问题:不能作为应用总路由

eg:app_test应用在项目urls.py

url(r'^app-test/',include('app_test.urls')) 末尾不能加$,因为作为应用总目录,是有下一级,如果用$标识结尾了,就代表不能有下一级路由

<h3 id="地址捕获">地址捕获
<pre># urls.py配置路由
url(r'^test/(\d+)/\d+/(\d+)/$',app_view.test)

对应请求路径

http://127.0.0.1:8000/test/1/22/333/

对应响应函数

def test(request,arg1,arg2):

arg1: str 1

# arg2: str 333
return HttpResponse('test')</code></pre>

<h3 id="小结">小结
<pre># 常规路由配置

r'^index/$'

r'^page/2/$'

应用路由配置

r'^app/'

根路由配置

r'^$'

路由配置均以 / 结尾

()中的字段会被请求响应函数捕获

限制响应函数捕获的变量名

(?P[0-9]+) 响应函数参数(requset,num)

Django 系列博客(一)

Django 系列博客(一)

Django 系列博客(一)

前言

学习了 python 这么久,终于到了Django 框架。这可以说是 python 名气最大的web 框架了,那么从今天开始会开始从 Django框架的安装到使用一步步的学习,这系列博客不会像前端的那样水了(立个 flag),希望可以成为高质量的博客。那么本篇博客介绍 Django 的安装以及如何在电脑上运行第一个 Django 应用。

Django 的安装

Django 的安装很简单,在 win 和 mac 上面都可以使用 pip 安装命令安装,也可以通过 pycharm 安装,或者下载文件在命令行使用安装工具安装。

接下来我在 ubuntu 上安装做示例。

在这里还安装了一个依赖包 pytz。这是用来做时区转换的一个第三方库。

其他平台的 pip 安装方式一样,不过要选用 python3的对应 pip 来安装,因为现在的 Django 版本已经不支持 python2了。

虚拟环境的安装

什么是虚拟环境

  • 对真实的 python 解释器的一个拷贝版本
  • 事实有效,可以独立存在并运行解释 python 代码
  • 可以在计算机上拷贝多个虚拟环境

为什么要使用虚拟环境

  • 保证真实环境的纯净性
  • 框架的多版本共存
  • 方便做框架的版本迭代
  • 降低多框架共存的维护成本

安装虚拟环境

  1. 通过 pip 安装虚拟环境库

因为我之前已经下载好了,所以这里直接显示请求已经完成,并且后面是安装的绝对路径。

  1. 前往目标文件夹

这个文件夹是你用来保存虚拟环境的文件夹,该文件夹一旦确定就不要轻易更改。

image-20190103154126721

这个 py3-env1是创建的一个纯净虚拟环境。

  1. 创建纯净的虚拟环境
virtualenv 虚拟环境名 (py3-env2)
  1. 终端启动虚拟环境
cd py3-env1\Scripts
activate
  1. 进入虚拟环境下的 python 开发环境
python3
  1. 关闭虚拟环境
deactivate
  1. Pycharm的开发配置
添加:创建项目 -> Project Interpreter -> Existing interpreter -> Virtualenv Environment | System Interpreter -> 目标路径下的 python.exe
删除:Setting -> Project -> Project Interpreter -> Show All

mac 电脑从第三步直接到最后一步就好

了解

# 创建非纯净环境:
#	-- virtualenv-clone 本地环境 虚拟环境名
# Mac配置终端,在终端运行虚拟环境
# 在用户根目录下的.bash_profile(没有需手动创建)文件中设置
# alias 终端指令名(env-py3)=''/Library/Virtualenv/虚拟环境名/bin/python3''
# alias 终端指令名(env-pip3)=''/Library/Virtualenv/虚拟环境名/bin/pip3''

HTTP 协议

因为 Django 框架应用层是采用的 HTTP 协议,所以有必要了解 HTTP 协议。

什么是 HTTP 协议

  • HTTP(HyperText Transport Protocol) 是超文本传输协议,而 HTTPS 也归属于 HTTP 协议,S 代表安全。
  • 基于 TCP/IP协议基础上的应用层协议,底层实现仍为 socket
  • 基于请求-响应模式:通信一定是从客户端开始,服务端接收到客户端一定会做出对应响应
  • 无状态:协议不对任何一次通信状态和任何数据做保存
  • 无连接:一次连接只完成一次请求-响应,请求-响应完毕后会立即断开连接。

HTTP 工作原理

一次 HTTP 连接称之为一个事务,过程可以分为四步

  1. 客户端与服务端建立连接
  2. 客户端发生一个 HTTP 协议指定格式的请求
  3. 服务端接收请求后,回应一个 HTTP 协议指定格式的响应
  4. 客户端将服务端的响应展现给用户

HTTP 状态码

  • 1开头:

  • 2开头:

  • 3开头:

  • 4开头:

  • 5开头:

请求报文

# 请求行  请求头  请求体
''''''
POST / HTTP/1.1\r\n
Host: 127.0.0.1:8001\r\n
Connection: keep-alive\r\n
Upgrade-Insecure-Requests: 1\r\n
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\n
Accept-Encoding: gzip, deflate, br\r\n
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8\r\n
\r\n
usr=abc&pwd=123
''''''

响应报文

# 响应行  响应头  响应体
''''''
HTTP/1.1 200 OK\r\n
Content-type:text/html\r\n
\r\n
Login Success
''''''

使用原生 socket 完成和浏览器的交互

目录结构

01_socket
	-- 01_client.html:前台通过form表单访问后台的页面
	-- 01_login.html:后台测试渲染给前台的登录页面
	-- 01_index.html:后台测试渲染给前台的主页
	-- 01_server.py:后台服务器文件

因为 B/S架构的客户端已经由浏览器写好,所以只需要关注服务器端就ok。

服务器端代码

from socket import socket

# 设置响应头(包含响应行)
RESP_HEADER = b''HTTP/1.1 200 OK\r\nContent-type:text/html;charset=utf-8\r\n\r\n'' # 连续两个\r\n表示响应头结束

# 设置服务器 socket 相关信息
server = socket()
server.bind('''', 8080) # 空字符串表示绑定本机
server.listen(5)
print((''服务:http://localhost:8080''))

while True:
    # 获取以 http 协议发来的请求
    client, addr = server.accept()
    data = client.recv(1024)
    # 数据报文 包含请求行 请求头 请求体
    print(data)
    client.send(RESP_HEADER)
    
    # /index => 响应主页
    # /login => 登录页面
    # 错误 => 404
    # 数据 data, 字节形式 => 字符串形式
    strData = str(data, encodeing)
    
    # 解析请求的数据,分析得到路由
    my_route = strData.split(''\r\n'')[0].split('' '')[1]
    
    # 后台没有设置的路由,统统由404来处理
    dt = b''404''
    
    # 设置的路由返回响应的页面文件
    if my_route == ''/index'':
        with open(''index 页面路径'', ''rb'') as f:
            dt = f.read()
    if my_route == ''/login'':
        with open(''login 页面路径'', ''rb'') as f:
            dt = f.read()
            
    # /favicon.ico该请求是往后台请求标签图标
    if my_route == ''/favicon.ico'':
        with open(''favicon.ico'', ''rb'') as f:
            dt = f.read()
    # 服务器发送响应体
    client.send(dt)
    # 一次循环,代表一次响应,也就是一次事务的完成,要关闭 http 请求连接
    client.close()

修改返回数据,完善响应体

# 字符串
client.send(b''HTTP/1.1 200 OK\r\n'')
client.send(b''\r\n'')
client.send(b''Normal Socket Web'')
# html代码,请求头要设置支持 html 代码
client.send(b''HTTP/1.1 200 OK\r\n'')
client.send(b''Content-type:text/html\r\n'')
client.send(b''\r\n'')
client.send(b''<h1>Normal Socket Web</h1>'')
# html文件(同级目录建立一个index.html页面)
client.send(b''HTTP/1.1 200 OK\r\n'')
client.send(b''Content-type:text/html\r\n'')
client.send(b''\r\n'')
# 利用文件方式读取页面
with open(''01_index.html'', ''rb'') as f:
    dt = f.read()
client.send(dt)

拓展

修改接收数据,模拟后台路由

# 分析接收到的数据
data = client.recv(1024)
# 保证接收到的数据作为字符串进行以下处理
data = str(data, encoding=''utf-8'')
# 拆分出地址位
route = data.split(''\r\n'')[0].split('' '')[1]
# 匹配地址,做出不同的响应
if route == ''/index'':
    with open(''01_index.html'', ''rb'') as f:
    	dt = f.read()
elif route == ''/login'':
    with open(''01_login.html'', ''rb'') as f:
    	dt = f.read()
else:
    dt = b''404''
client.send(dt)

框架演变

目录结构

02_frame
	-- favicon.ico
	-- index.html
	-- manage.py

manage.py

import socket
import pymysql
# 响应头
RESP_HEADER = b''HTTP/1.1 200 OK\r\nContent-type:text/html\r\n\r\n''

# 请求处理
def index():
    # 以字节方式读取文件
    with open(''index.html'', ''rb'') as f:
        dt = f.read()
    return dt
def ico():
    with open(''favicon.ico'', ''rb'') as f:
        dt = f.read()
    return dt
def user():
    # 数据库操作
    conn = pymysql.connect(host=''127.0.0.1'', port=3306, db=''django'', user=''root'', password=''root'')
    cur = conn.cursor(pymysql.cursors.DictCursor)
    cur.execute(''select * from user'')
    users = cur.fetchall()
    print(users)
    users = ''''''%d:%s
    %d:%s'''''' % (users[0][''id''], users[0][''name''], users[1][''id''], users[1][''name''])
    return users.encode(''utf-8'')

# 设置路由
urls = {
    # 请求路径与请求处理函数一一对应
    ''/index'': index,
    ''/favicon.ico'': ico,
    ''/user'': user
}

# 设置socket
def serve(host, port):
    server = socket.socket()
    server.bind((host, port))
    print(''start:http://'' + host + '':'' + str(port))
    server.listen(5)
    while True:
        sock, addr = server.accept()
        data = sock.recv(1024)
        data = str(data, encoding=''utf-8'')
        print(data)
        route = data.split(''\r\n'')[0].split('' '')[1]

        resp = b''404''
        if route in urls:
            resp = urls[route]()

        sock.send(RESP_HEADER)
        sock.send(resp)
        sock.close()

# 启服务
if __name__ == ''__main__'':
    serve(''127.0.0.1'', 8002)

项目演变

目录结构

03_proj
	-- template
		-- index.html
		-- user.html
	favicon.ico
	start.py
	urls.py
	views.py

index.html

<h1>{{ name }}</h1>

user.html

<table border="1">
    <tr>
        <th>id</th>
        <th>name</th>
        <th>password</th>
    </tr>
    {% for user in users%}
    <tr>
        <td>{{user.id}}</td>
        <td>{{user.name}}</td>
        <td>{{user.password}}</td>
    </tr>
    {% endfor %}
</table>

start.py

from wsgiref.simple_server import make_server
from urls import urls


def app(env, response):
    print(env)
    # 设置响应头
    response("200 OK", [(''Content-type'', ''text/html'')])
    route = env[''PATH_INFO'']
    print(route)
    data = urls[''error'']()
    if route in urls:
        data = urls[route]()
    # 返回二进制响应体
    return [data]


if __name__ == ''__main__'':
    server = make_server(''127.0.0.1'', 8003, app)
    print(''start:http://127.0.0.1:8003'')
    server.serve_forever()

urls.py

from views import *
urls = {
    ''/index'': index,
    ''/favicon.ico'': ico,
    ''/user'': user,
    ''error'': error
}

views.py

import pymysql
# 利用jinja2来渲染模板,将后台数据传给前台
from jinja2 import Template

def index():
    with open(''templates/index.html'', ''r'') as f:
        dt = f.read()
    tem = Template(dt)
    resp = tem.render(name=''主页'')
    return resp.encode(''utf-8'')

def ico():
    with open(''favicon.ico'', ''rb'') as f:
        dt = f.read()
    return dt

def user():
    # 数据库操作
    conn = pymysql.connect(host=''127.0.0.1'', port=3306, db=''django'', user=''root'', password=''root'')
    cur = conn.cursor(pymysql.cursors.DictCursor)
    cur.execute(''select * from user'')
    users = cur.fetchall()
    print(users)

    with open(''templates/user.html'', ''r'') as f:
        dt = f.read()
    tem = Template(dt)
    resp = tem.render(users=users)

    return resp.encode(''utf-8'')

def error():
    return b''404''

Django 系列博客(七)

Django 系列博客(七)

Django 系列博客(七)

前言

本篇博客介绍 Django 中的视图层中的相关参数,HttpRequest 对象、HttpResponse 对象、JsonResponse,以及视图层的两种响应方式 CBV 和 FBV,还有简单的文件上传。

视图函数

一个视图函数,简称视图,是一个简单的Python 函数,它接受Web请求并且返回Web响应。响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. . . 是任何东西都可以。无论视图本身包含什么逻辑,都要返回响应。代码写在哪里也无所谓,只要它在你的Python目录下面。除此之外没有更多的要求了——可以说“没有什么神奇的地方”。为了将代码放在某处,约定是将视图放置在项目或应用程序目录中的名为views.py的文件中。

下面是一个返回当前日期和时间作为 HTML 文档的视图:

from django.shortcuts import render, HttpResponse, HttpResponseRedirect, redirect
import datetime

def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)

这段代码解析:

  • django.shortcuts模块导入了HttpResponse类,以及Python的datetime库;
  • 定义了current_datetime函数。它就是视图函数。每个视图函数都使用HttpRequest对象作为第一个参数,并且通常称之为request

注意,视图函数的名称并不重要;不需要用一个统一的命名方式来命名,以便让Django识别它。我们将其命名为current_datetime,是因为这个名称能够精确地反映出它的功能。

  • 会返回一个HttpResponse对象,其中包含生成的响应。每个视图函数都负责返回一个HttpResponse对象。

在视图层最重要的就是要熟悉两个对象:请求对象(request)和响应对象(HttpResponse)。

HttpRequest 对象

request 属性

Django 将请求报文中的请求行、请求头、请求体封装成 HttpRequest 类中的属性。除了特殊说明之外,其他的均为只读属性。

1.HttpRequest.GET

  一个类似于字典的对象,包含 HTTP GET 的所有参数。详情请参考 QueryDict 对象。

2.HttpRequest.POST

  一个类似于字典的对象,如果请求中包含表单数据,则将这些数据封装成 QueryDict 对象。

  POST 请求可以带有空的 POST 字典 —— 如果通过 HTTP POST 方法发送一个表单,但是表单中没有任何的数据,QueryDict 对象依然会被创建。
   因此,不应该使用 if request.POST  来检查使用的是否是POST 方法;应该使用 if request.method == "POST"
  另外:如果使用 POST 上传文件的话,文件信息将包含在 FILES 属性中。
   
   注意:键值对的值是多个的时候,比如checkbox类型的input标签,select标签,需要用:
        request.POST.getlist("hobby")

3.HttpRequest.body

  一个字符串,代表请求报文的主体。在处理非 HTTP 形式的报文时非常有用,例如:二进制图片、XML,Json等。
  但是,如果要处理表单数据的时候,推荐还是使用 HttpRequest.POST 。


4.HttpRequest.path

  一个字符串,表示请求的路径组件(不含域名)。
  例如:"/music/bands/the_beatles/"

5.HttpRequest.method

  一个字符串,表示请求使用的HTTP 方法。必须使用大写。
  例如:"GET"、"POST"


6.HttpRequest.encoding

  一个字符串,表示提交的数据的编码方式(如果为 None 则表示使用 DEFAULT_CHARSET 的设置,默认为 ''utf-8'')。
   这个属性是可写的,你可以修改它来修改访问表单数据使用的编码。
   接下来对属性的任何访问(例如从 GET 或 POST 中读取数据)将使用新的 encoding 值。
   如果你知道表单数据的编码不是 DEFAULT_CHARSET ,则使用它。


7.HttpRequest.META

   一个标准的Python 字典,包含所有的HTTP 首部。具体的头部信息取决于客户端和服务器,下面是一些示例:
  取值:

    CONTENT_LENGTH —— 请求的正文的长度(是一个字符串)。
    CONTENT_TYPE —— 请求的正文的MIME 类型。
    HTTP_ACCEPT —— 响应可接收的Content-Type。
    HTTP_ACCEPT_ENCODING —— 响应可接收的编码。
    HTTP_ACCEPT_LANGUAGE —— 响应可接收的语言。
    HTTP_HOST —— 客服端发送的HTTP Host 头部。
    HTTP_REFERER —— Referring 页面。
    HTTP_USER_AGENT —— 客户端的user-agent 字符串。
    QUERY_STRING —— 单个字符串形式的查询字符串(未解析过的形式)。
    REMOTE_ADDR —— 客户端的IP 地址。
    REMOTE_HOST —— 客户端的主机名。
    REMOTE_USER —— 服务器认证后的用户。
    REQUEST_METHOD —— 一个字符串,例如"GET" 或"POST"。
    SERVER_NAME —— 服务器的主机名。
    SERVER_PORT —— 服务器的端口(是一个字符串)。
   从上面可以看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 之外,请求中的任何 HTTP 首部转换为 META 的键时,
    都会将所有字母大写并将连接符替换为下划线最后加上 HTTP_  前缀。
    所以,一个叫做 X-Bender 的头部将转换成 META 中的 HTTP_X_BENDER 键。

8.HttpRequest.FILES

  一个类似于字典的对象,包含所有的上传文件信息。
   FILES 中的每个键为<input type="file" name="" /> 中的name,值则为对应的数据。
  注意,FILES 只有在请求的方法为POST 且提交的<form> 带有enctype="multipart/form-data" 的情况下才会
   包含数据。否则,FILES 将为一个空的类似于字典的对象。


9.HttpRequest.COOKIES

  一个标准的Python 字典,包含所有的cookie。键和值都为字符串。



10.HttpRequest.session

   一个既可读又可写的类似于字典的对象,表示当前的会话。只有当Django 启用会话的支持时才可用。
    完整的细节参见会话的文档。


11.HttpRequest.user(用户认证组件下使用)

  一个 AUTH_USER_MODEL 类型的对象,表示当前登录的用户。

  如果用户当前没有登录,user 将设置为 django.contrib.auth.models.AnonymousUser 的一个实例。你可以通过 is_authenticated() 区分它们。

    例如:

    if request.user.is_authenticated():
        # Do something for logged-in users.
    else:
        # Do something for anonymous users.


       user 只有当Django 启用 AuthenticationMiddleware 中间件时才可用。

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

    匿名用户
    class models.AnonymousUser

    django.contrib.auth.models.AnonymousUser 类实现了django.contrib.auth.models.User 接口,但具有下面几个不同点:

    id 永远为None。
    username 永远为空字符串。
    get_username() 永远返回空字符串。
    is_staff 和 is_superuser 永远为False。
    is_active 永远为 False。
    groups 和 user_permissions 永远为空。
    is_anonymous() 返回True 而不是False。
    is_authenticated() 返回False 而不是True。
    set_password()、check_password()、save() 和delete() 引发 NotImplementedError。
    New in Django 1.8:
    新增 AnonymousUser.get_username() 以更好地模拟 django.contrib.auth.models.User。

request常用方法

1.HttpRequest.get_full_path()

  返回 path,如果可以将加上查询字符串。

  例如:"/music/bands/the_beatles/?print=true"
  注意和path的区别:http://127.0.0.1:8001/order/?name=lqz&age=10

2.HttpRequest.is_ajax()

  如果请求是通过XMLHttpRequest 发起的,则返回True,方法是检查 HTTP_X_REQUESTED_WITH 相应的首部是否是字符串''XMLHttpRequest''。

  大部分现代的 JavaScript 库都会发送这个头部。如果你编写自己的 XMLHttpRequest 调用(在浏览器端),你必须手工设置这个值来让 is_ajax() 可以工作。

  如果一个响应需要根据请求是否是通过AJAX 发起的,并且你正在使用某种形式的缓存例如Django 的 cache middleware,
   你应该使用 vary_on_headers(''HTTP_X_REQUESTED_WITH'') 装饰你的视图以让响应能够正确地缓存。

HttpResponse 对象

响应对象主要有三种形式:前面的博客有相关介绍

  1. HttpResponse();
  2. render();
  3. redirect().

HttpResponse()括号内直接跟一个具体的字符串作为响应体,比较直接和简单,所以这里介绍后两种

render()

render(request, template_name[, context])

结合给定的模板和一个上下文字典,返回一个经过 Django渲染后的HttpResponse 对象到前端。

参数:

  1. request:用于生成响应的请求对象;
  2. template_name:要使用的模板的完整名称,可选的参数;
  3. context:添加到模板上下文的一个字典。默认是一个空字典,如果字典中的某个值是可调用的,视图将在渲染模板之前调用它;

render 方法就是将一个模板页面中的模板语法进行渲染,最终渲染成一个 HTML 页面作为响应返回给前端。

redirect()

传递要重定向的一个硬编码的URL

def my_view(request):
    ...
    return redirect(''/some/url/'')

也可以是一个完成的 url

def my_view(request):
    ...
    return redirect(''http://www.baidu.com/'') 

JsonResponse对象

向前端返回一个 json 格式的字符串,有两种方式:

第一种方式

import json
data = {''name'': ''musibii'', ''age'': 18}
return HttpResponse(json.dumps(data))
# 从这里可以看出其实 Jsonresponse内部也是调用了 json 的 dumps 方法进行转换

第二种方式

from django.http import JsonResponse
data = {''name'': ''musibii'', ''age'': 18}

return JsonResponse(data1,safe=False)
# safe参数是一种安全机制,因为如果要传输列表类型的数据时,会因为内部的相关机制会产生错误。

CBV 和 FBV

CBV 基于类的视图(Class Base View)和 FBV 基于函数的视图(Function Base View)

CBV

from django.views import View

class Login(View):
    
    def dispatch(self, request, *args, **kwargs):
        print(request)
        print(args)
        print(kwargs)
        # 可以写类似装饰器的东西,在前后加代码
        obj=super().dispatch(request, *args, **kwargs)
        return obj

    def get(self, request):
        return render(request, ''login.html'')

    def post(self, request):
        name = request.POST.get(''name'')
        ret = BookInfo.objects.filter(name=name).first()
        print(type(ret))
        dic = {}
        print(ret.name)
        print(type(ret.__dict__))
        for key, value in (ret.__dict__).items():
            if key[0].startswith(''_''):
                continue
            print(key)
            dic[key] = value
            # print(dic)
       
       # 第二种
       # ret = BookInfo.objects.all() 
       # lis = []
       # for info in ret:
       #     dic = {}
       #     for k, v in (info.__dict__).items():
       #         if key[0].startswitch(''''):
       #             continue
       #         dic[key] = v
       #     lis.append(dic)

       # 第三种
       # li = []
       # ret = BookInfo.objects.all()
       # for book in ret:
       #     dic = {}
       #     for field in book._meta.fields:
       #         dic[field.name] = getattr(book, field.name)
       #     li.append(dic)
       return JsonResponse(dic, json_dumps_params={''ensure_ascii'': False})

FBV

def file_upload(request):
    if request.method=="GET":
        return render(request,''file_upload.html'')
    else:
        print(request.POST)
        print(request.FILES)
        # print(request.body)
        # FILES是一个字典,
        # <MultiValueDict: {''myfile'': [<InMemoryUploadedFile: 1.jpg (image/jpeg)>]}>
        # 拿到上传的文件对象

        file=request.FILES.get(''myfile'')
        print(type(file))
        from django.core.files.uploadedfile import InMemoryUploadedFile
        with open(file.name,''wb'') as f:
            # for line in file.chunks():
            for line in file:
                f.write(line)
        return HttpResponse(''上传成功'')

简单文件上传

模板文件

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

<form action="" method="post" enctype="multipart/form-data">
    <p>用户名:<input type="text" name="name"></p>
    <input type="file" name="myfile">
{#    <input type="file" name="myfile2">#}
    <input type="submit" value="提交">

</form>

</body>
</html>

路由文件

from django.conf.urls import url
from app01 import views
urlpatterns = [
	url(r''^upload_file/$'', views.UploadFile.as_view()),
]

视图文件

class UploadFile(View):

    def get(self, request):
        return render(request, ''upload_file.html'')

    def post(self, request):
        file = request.FILES.get(''myfile'')
        # print(file[''file''])
        from django.core.files.uploadedfile import InMemoryUploadedFile
        print(time.time())
        filename = str(time.time()).split(''.'')[0] + file.name
        with open(filename, ''wb'') as f:
            for line in file:
                f.write(line)
        return HttpResponse(''上传成功'')

Django 系列博客(三)

Django 系列博客(三)

Django 系列博客(三)

前言

本篇博客介绍 django 的前后端交互及如何处理 get 请求和 post 请求。

get 请求

get请求是单纯的请求一个页面资源,一般不建议进行账号信息的传输。

配置路由

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

import app.views as app_views
import newApp.views as new_views
urlpatterns = [
    url(r''^admin/'', admin.site.urls),
    url(r''^$'', app_views.home),
    # 路由采用正则匹配, ^以什么开头 $以什么结果
    # 注: 当路由没有子路由是,才在末尾添加$
    url(r''^index/$'', app_views.index),
    url(r''login'', app_views.login_action),
    url(r''^new/index/$'', new_views.index)
]

配置视图

from django.shortcuts import render, redirect

from django.http import HttpResponse

# Create your views here.

# 每一个请求,都对应一个视图响应函数,来出现请求,完成响应
# def index(abc):
#     return HttpResponse(''hello django'')  # 第一个响应

import django.core.handlers.wsgi
def login_action(request):
    return render(request, ''login.html'') # 第一个响应页面

# def home(request):
#     return redirect(''/index/'') # 第一个重定向

def home(request):
    return render(request, ''index.html'')

def index(request):
    return redirect(''/'')

配置页面资源

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>主页</title>
</head>
<body>
    <h1>app的主页</h1>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
    <h1>登录</h1>
</body>
</html>

post 请求

配置路由

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

from app import views

urlpatterns = [
    url(r''^admin/'', admin.site.urls),
    url(r''^$'', views.home),
    url(r''^index/$'', views.index),
    url(r''^login/$'', views.login, name=''lg''),
]

配置视图

from django.shortcuts import render, redirect
import pymysql

# Create your views here.

def home(request):
    return render(request, ''index.html'')

def index(request):
    return redirect(''/'')

''''''
def login(request):
    print(request.method)
    # 如果获取GET请求的提交数据
    # import django.core.handlers.wsgi
    # print(type(request))
    # import django.http.request.QueryDict
    # print(type(request.GET))
    print(request.GET)
    # usr = request.GET[''usr'']  # 不安全
    usr = request.GET.get(''usr'', ''USR'') # 安全, 第一个参数为数据的key, 第二个参数为默认值
    print(usr)
    pwd = request.GET.get(''pwd'') # 不设默认值,没有取到值时,返回值为None
    print(pwd)
    return render(request, ''login.html'')
''''''

from django.http import HttpResponse

def login(request):
    if request.method == ''GET'':
        stus = request.GET.getlist(''stu'')
        print(stus)
        return render(request, ''login.html'')

    # 没有GET分支, 发来的请求为POST
    usr = request.POST.get(''usr'')
    pwd = request.POST.get(''pwd'')
    print(usr, pwd)

    # 连接数据库 => ORM
    conn = pymysql.connect(host=''localhost'', port=3306, user=''root'', password=''root'', db=''django'')
    cur = conn.cursor(pymysql.cursors.DictCursor)
    # cur.execute(''select * from user'')
    # users = cur.fetchall()
    cur.execute(''select * from user where usr=%s and pwd=%s'', [usr, pwd])
    res = cur.fetchone()
    print(res)
    if res != None:
        return HttpResponse(''登录成功'')
    return HttpResponse(''登录失败'')

配置页面资源

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>主页</title>
{#    <link rel="stylesheet" href="./index.css">#}
{#    <link rel="stylesheet" href="/static/index.css">#}
{#    <link rel="stylesheet" href="/static/temp.css">#}

{#    <link rel="stylesheet" href="/ooo/index.css">#}
{#    <link rel="stylesheet" href="/ooo/temp.css">#}

{#    <link rel="stylesheet" href="/static/css/test.css">#}

    <link rel="stylesheet" href="/static/css/index.css">
</head>
<body>
    <h1>主页</h1>
    <img src="/static/img/001.png" alt="">
</body>
</html>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>登录</title>
    <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css">
    <style>
        .box {
            border: 1px solid #ccc;
            padding: 20px;
            border-radius: 20px;
            height: 380px;
        }
    </style>
</head>
<body>
{#<button> 按钮</button>#}
{#<div>#}
{#    <buttontype="button" data-toggle="dropdown" aria-haspopup="true"#}
{#            aria-expanded="false">#}
{#        Large button <span></span>#}
{#    </button>#}
{#    <ul>#}
{#        <li><a href="#">Action</a></li>#}
{#        <li><a href="#">Another action</a></li>#}
{#        <li><a href="#">Something else here</a></li>#}
{#        <li role="separator"></li>#}
{#        <li><a href="#">Separated link</a></li>#}
{#    </ul>#}
{#</div>#}

<div>
    <div>
        {# action: 没写 | http://localhost:8801/login | /login/ | {% url ''url_name'' %} #}
        <form action="{% url ''lg'' %}" method="GET">
{#            {% csrf_token %}#}
            <div>
                <label for="usr">用户名:</label>
                <input type="text"name="usr" id="usr" placeholder="请输入用户名">
            </div>
            <div>
                <label for="pwd">Password</label>
                <input type="password"name="pwd" id="pwd" placeholder="请输入密码">
            </div>
            <div>
                <label>
                    <input name="stu" type="checkbox" value="stu1"> 学生1
                </label>
                <label>
                    <input name="stu" type="checkbox" value="stu2"> 学生2
                </label>
                <label>
                    <input name="stu" type="checkbox" value="stu3"> 学生3
                </label>
            </div>
            <button type="submit">登录</button>
        </form>
    </div>
</div>
{#<a href="/index/">前往主页</a>#}
</body>
<script src="/static/bootstrap-3.3.7-dist/js/jquery-3.3.1.js"></script>
<script src="/static/bootstrap-3.3.7-dist/js/bootstrap.js"></script>
</html>

前后端交互

Django请求生命周期

Django 系列博客(九)

Django 系列博客(九)

<h1 id="django-系列博客九">Django 系列博客(九)
<h2 id="前言">前言

本篇博客介绍 Django 模板的导入与继承以及导入导入静态文件的几种方式。

语法:``{% include '模板名称' %}

如下:

<Meta charset="UTF-8"> index dist/css/bootstrap.css"> </div> <div&gt; <div&gt; {% block right %} {% endblock %} </div> {% block content %} {% endblock %} </div> </div>

我们今天的关于Django 系列博客的分享就到这里,谢谢您的阅读,如果想了解更多关于Django 系列博客(一)、Django 系列博客(七)、Django 系列博客(三)、Django 系列博客(九)的相关信息,可以在本站进行搜索。

本文标签:

上一篇Django 系列博客(七)(django blog)

下一篇搭建你的第一个Django应用程序(简述搭建django开发环境所需要的步骤)