python 全栈开发,Day67(Django简介)

2023-10-25 14:20

本文主要是介绍python 全栈开发,Day67(Django简介),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

昨日内容回顾

1. socket创建服务器2. http协议:请求协议请求首行     请求方式 url?a=1&b=2  协议请求头       key:value请求体       a=1&b=2(只有post请求才有请求体)响应协议 响应首行    协议 状态码 文本响应头      key:value响应体      html字符串3. wsgiref模块(基于wsgi协议)功能:1. 按着http协议请求格式解析请求数据----envision:{} 2. 按着http协议响应格式封装响应数据----response    4 基于wsgiref实现了一个简单web框架1. urls : 存放路由关系2 views: 存放视图函数3 templates: 存放html文件4 wsgi-sever:启动文件

 

一、Django简介

知识预览

  • MVC与MTV模型

  • Django的下载与基本命令

  • 基于Django实现的一个简单示例

 

MVC与MTV模型

MVC

Web服务器开发领域里著名的MVC模式,所谓MVC就是把Web应用分为模型(M),控制器(C)和视图(V)三层,他们之间以一种插件式的、松耦合的方式连接在一起,模型负责业务对象与数据库的映射(ORM),视图负责与用户的交互(页面),控制器接受用户的输入调用模型和视图完成用户的请求,其示意图如下所示:

mvc主要用于web框架,常用的开发语言,有java,php,node.js等等。

web框架应用最广泛就是PHP了,它只能做web开发,而且开发效率很快。

 

MTV

Django的MTV模式本质上和MVC是一样的,也是为了各组件间保持松耦合关系,只是定义上有些许不同,Django的MTV分别是值:

M 代表模型(Model): 负责业务对象和数据库的关系映射(ORM)。
T 代表模板 (Template):负责如何把页面展示给用户(html)。
V 代表视图(View): 负责业务逻辑,并在适当时候调用Model和Template。
除了以上三层之外,还需要一个URL分发器,它的作用是将一个个URL的页面请求分发给不同的View处理,View再调用相应的Model和Template,MTV的响应模式如下所示:

一般是用户通过浏览器向我们的服务器发起一个请求(request),这个请求回去访问视图函数,(如果不涉及到数据调用,那么这个时候视图函数返回一个模板也就是一个网页给用户),视图函数调用模型,模型去数据库查找数据,然后逐级返回,视图函数把返回的数据填充到模板中空格中,最后返回网页给用户。

 

这里面最难的部分就是model,后面会慢慢讲到。

django 有一个ORM,它是专门来操作数据库的。这套语法,需要大量练习才能掌握。

 

MVC和MTV模型的区别:

MVC:M : model (与数据库打交道)V :  views  (存放html文件)C : Controller(逻辑控制部分)        
MTV M : model     (与数据库打交道)T : templates    (存放html文件)    V : views      (逻辑处理)+路由控制层(分发哪一个路径由哪一个视图函数处理),它没有单独的分层。它作为URL分发器,将url请求分发给不同的view处理

 

Django的下载与基本命令

1、下载Django:

pip3 install django

2、创建一个django project

windows用户,以管理员身份打开一个cmd窗口。进入一个空目录,运行以下命令:

E:\python_script\django框架\day2>django-admin startproject mysite

当前目录下会生成mysite的工程,目录结构如下:

mysite/
├── manage.py
└── mysite├── __init__.py├── settings.py├── urls.py└── wsgi.py

manage.py ----- Django项目里面的工具,通过它可以调用django shell和数据库等。
settings.py ---- 包含了项目的默认设置,包括数据库信息,调试标志以及其他一些工作的变量。
urls.py ----- 负责把URL模式映射到应用程序。

 

manage.py : 它不关是启动文件,它还是与Django交互的文件。比如:

python manage.py  runserver   : 运行项目
python manage.py  startapp    : 创建应用

如果运行项目时,不指定端口,默认监听本机的8000端口。

3、在mysite目录下创建应用

#进入mysite目录
E:\python_script\django框架\day2>cd mysite
#创建应用blog
E:\python_script\django框架\day2\mysite>python manage.py startapp blog

目录结构如下:

mysite/
├── blog
│   ├── admin.py
│   ├── apps.py
│   ├── __init__.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── manage.py
└── mysite├── __init__.py├── settings.py├── urls.py└── wsgi.py

views.py---存放视图函数

models--与数据库打交道

还有一个目录templates,它是用来存放html文件的,下面会讲到。

 

从上面的目录结构可以看出,mysite目录下有一个blog。那么顶层的mysite,叫做 项目。底层的blog叫做应用。

比如微信是一个项目。聊天,朋友圈,支付...都是应用。
项目是必须包含应用的,项目可以包含多个应用。

mysite下的mysite,是全局文件,它有2个全局配置文件,一个是settings.py(项目配置文件),一个是urls.py(路由控制文件)。

wsgi.py是封装socket,用来接收和响应请求的。这个文件,从来都不需要动。

 

4、启动django项目

E:\python_script\django框架\day2\mysite>python manage.py runserver 8080
Performing system checks...System check identified no issues (0 silenced).You have 14 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
June 21, 2018 - 19:33:29
Django version 2.0.6, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8080/
Quit the server with CTRL-BREAK.

这样我们的django就启动起来了!当我们访问:http://127.0.0.1:8080/时就可以看到:

基于Django实现的一个简单示例

url控制器

修改mysite目录下的urls.py,增加index路径

注意:index后面不要加括号。直接views.index即可

必须导入blog应用的views模块,否则它找不到对应的视图函数

from django.contrib import admin
from django.urls import path
from blog import viewsurlpatterns = [path('admin/', admin.site.urls),path('index/',views.index),
]
View Code

视图

修改blog目录下的views.py,增加index视图函数

from django.shortcuts import render
import datetime# Create your views here.def index(request):now=datetime.datetime.now()ctime=now.strftime("%Y-%m-%d %X")return render(request,"index.html",{"ctime":ctime})
View Code

request,它是一个对象。存储了请求信息,比如请求路径,请求方式,GET数据,POST数据...等等。

request参数必须要有,不管你用不用它。

 

模板

新建文件夹templates,在此目录创建index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><h4>当前时间:{{ ctime }}</h4></body>
</html>
View Code

修改mysite目录下的settings.py,指定模板目录为templates,修改部分如下:

TEMPLATES = [{'BACKEND': 'django.template.backends.django.DjangoTemplates','DIRS': [os.path.join(BASE_DIR, 'templates')],'APP_DIRS': 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',],},},
]
View Code

访问网页,效果如下:

 django有一个好处,代码更改之后,它会自动加载代码。而不需要重启django项目,网页就能更新了!

 

增加登录页面

修改mysite目录下的urls.py,新增一个login

urlpatterns = [path('admin/', admin.site.urls),path('index/',views.index),path('login/',views.login),
]
View Code

在templates目录下创建文件login.html

注意:form表单的标签名是form,不是from。from是MySQL的关键字,不要弄混淆了。否则点击提交按钮,是没有反应的。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<form action=""><lable>用户名</lable><input type="text" name="user"/><lable>用户名</lable><input type="password" name="pwd"/><input type="submit">
</form></body>
</html>
View Code

修改blog目录下的views.py,增加login视图函数

from django.shortcuts import render
import datetime# Create your views here.def index(request):now=datetime.datetime.now()ctime=now.strftime("%Y-%m-%d %X")return render(request,"index.html",{"ctime":ctime})def login(request):return render(request,"login.html")
View Code

访问登录页面,效果如下:

为什么render能找到login.html文件呢?
因为setting.py文件里面定义了template路径。render方法,是用来渲染模板的,它会从TEMPLATES配置的路径中去寻找html文件。

如果修改DIRS里面的文件名,比如改为abc

'DIRS': [os.path.join(BASE_DIR, 'abc')],

访问页面,会报错

重新修改回来,再次访问,就正常了。

 

修改urls.py,增加auth路径,用来做验证的。

urlpatterns = [path('admin/', admin.site.urls),path('index/',views.index),path('login/',views.login),path('auth/',views.auth),
]
View Code

修改login.html文件,改为post请求

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<form action="/auth/" method="post"><lable>用户名</lable><input type="text" name="user"/><lable>用户名</lable><input type="password" name="pwd"/><input type="submit">
</form></body>
</html>
View Code

修改views.py文件,增加auth视图函数

from django.shortcuts import render,HttpResponse
import datetime# Create your views here.def index(request):now=datetime.datetime.now()ctime=now.strftime("%Y-%m-%d %X")return render(request,"index.html",{"ctime":ctime})def login(request):return render(request,"login.html")def auth(request):print(request.path)  # 路径print(request.method)  # 请求方式print(request.GET)  # GET数据print(request.POST)  # POST数据return HttpResponse("OK")
View Code

访问登录页面,输入数据,点击提交

页面输出403,被CSRF拦截了。

CSRF:跨站请求伪造,常缩写为CSRF或者XSRF,是一种对网站的恶意利用。

后面的课程会讲到,如何避免CSRF。修改settings.py里面的MIDDLEWARE 配置项,关闭CSRF

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',
]
View Code

 

访问方式

访问方式有2种,GET和POST

在地址栏中,只有GET请求。

在form表单中,有GET和POST。它是根据method属性决定的!一般表单使用POST

 

再次访问url,输入表单信息,点击提交。

输出ok,表示正常。注意:这里还没有做登录认证,下面会讲到!

查看cmd窗口输出信息:

/auth/
POST
<QueryDict: {}>
<QueryDict: {'user': ['xiao'], 'pwd': ['123']}>

可以看到:

路径:/auth/。请求方式: POST。GET数据为空。POST数据是一个字典。

 

地址栏直接输入:

http://127.0.0.1:8080/auth/?u=xiao,sex=m

查看cmd窗口输出信息:

/auth/
GET
<QueryDict: {'u': ['xiao,sex=m']}>
<QueryDict: {}>

 

登录认证

正常网站,用户名和密码是保存在数据库中。由于还没有学到django连接数据库,所以这里将用户名和密码写死,模拟登录行为。

修改views.py,获取用户和密码,进行判断。

from django.shortcuts import render,HttpResponse
import datetime# Create your views here.def index(request):now=datetime.datetime.now()ctime=now.strftime("%Y-%m-%d %X")return render(request,"index.html",{"ctime":ctime})def login(request):return render(request,"login.html")def auth(request):user = request.POST.get('user')  # 获取用户名pwd = request.POST.get('pwd') # 获取密码print(user,pwd)#判断用户名和密码if user == 'xiao' and pwd == '123':return HttpResponse("登录成功")  # 返回响应体给浏览器,显示"登录成功"文字else:return render(request,"login.html")  # 返回响应体-->login.html文件内容
View Code

重新访问登录页面,输入正确的用户名和密码

页面提示,成功。

 

访问过程分析

访问登录页面时,经历3个步骤
(1) http://127.0.0.1:8000/login/   get请求 无数据
(2) path('login/',views.login),    调转视图函数login(request)
(3) login                          执行视图函数,响应了一个login.html页面

解释:

1. 首先是用户在浏览器输入url:http://127.0.0.1:8000/login/

2. django接收到请求之后,根据URL控制器匹配视图函数

3. 执行视图函数login,响应请求给浏览器一个login.html页面。

 

查看views.py文件的login视图函数

render(request,"login.html")

上面的代码就是响应体。那么浏览器如何得到response信息的呢?封装response信息是由wsgi来完成的。

 

点击提交按钮的操作,也经历3个步骤
(1) http://127.0.0.1:8000/auth/   post请求,数据为user=xiao&pwd=123
(2) path('auth/',views.auth),    调取视图函数auth(request)
(3) auth      执行视图函数, if 登陆成功:响应一个字符串登陆成功。else:  响应了一个登陆页面

解释:

1. 虽然form的action属性值为"/auth/",但是执行提交动作时,浏览器会查看action属性,如果为相对路径。那么会获取当前url的域名/IP加端口。和action属性拼接,得到完整的url,比如:http://127.0.0.1:8000/auth/。将表单数据以POST方式发送给此url。

注意:推荐使用这种写法。如果action写成完整的url(比如:http://127.0.0.1:8000/auth/),遇到服务器迁移时。那么涉及到的html文件,都需要更改,非常耗时耗力!

如果采用相对路径方式,那么不需要改动代码,它会自动拼接,完美解决这个问题。

比如写/auth/,会自动拼接为http://127.0.0.1:8000/auth/

如果action为"",也就是空,它会拼接当前的完整ur。

比如访问登录页面,那么action的属性值为 当前url,比如:http://127.0.0.1:8000/login/

2. django接收到请求之后,根据URL控制器匹配视图函数auth

3. 执行视图函数,如果用户名和密码正确,页面显示登录成功。否则,页面还是显示登录页面。

 

上面提到的2个场景,它们之间,是没有任何关系的。

每一个请求,对于服务器而言,都是一个新的请求。

 

思考一个问题,能够将login和auth视图函数合并?

答案是可以的。

更改login.html,将action属性设置为空(参考上面的步骤1解释)

<form action="" method="post">

更改views.py,删除auth视图函数代码,修改login视图函数,完整代码如下:

from django.shortcuts import render,HttpResponse
import datetime# Create your views here.def index(request):now=datetime.datetime.now()ctime=now.strftime("%Y-%m-%d %X")return render(request,"index.html",{"ctime":ctime})def login(request):#判断请求是否为POST,必须为大写if request.method == "POST":user = request.POST.get('user')  # 获取用户名pwd = request.POST.get('pwd')  # 获取密码print(user, pwd)# 判断用户名和密码if user == 'xiao' and pwd == '123':return HttpResponse("登录成功")  # 返回响应体给浏览器,显示"登录成功"文字else:return render(request, "login.html")  # 返回响应体-->login.html文件内容return render(request,"login.html")  # 默认输出登录页面
View Code

修改urls.py,删除auth路径

urlpatterns = [path('admin/', admin.site.urls),path('index/',views.index),path('login/',views.login),
]
View Code

重新访问登录页面,输入正确的用户和密码,点击提交。页面输出:

这就用到了if分支。
能尽量合成视图函数的,推荐合成。如果逻辑简单,可以合成。
逻辑比较复杂的,还是建议分开。

 

视图函数,必须返回一个HttpResponse对象。HttpResponse是一个对象,对象里面,放字符串。

HttpResponse会自动将字符串转换为字节
django要求视图函数,必须返回一个HttpResponse对象。

 

模拟render操作

修改login函数,else部分是重点

def login(request):#判断请求是否为POST,必须为大写if request.method == "POST":user = request.POST.get('user')  # 获取用户名pwd = request.POST.get('pwd')  # 获取密码print(user, pwd)# 判断用户名和密码if user == 'xiao' and pwd == '123':return HttpResponse("登录成功")  # 返回响应体给浏览器,显示"登录成功"文字else:from mysite import settings  # 导入settings模块import os# 拼接login.html的绝对路径path = os.path.join(settings.BASE_DIR,"templates","login.html")with open(path,encoding="utf-8") as f:data = f.read()  # 读取文件所有内容print("data",data+'aaaaa')#返回给浏览器并加上一段话return HttpResponse(data+'用户名和密码错误')# return render(request, "login.html")  # 返回响应体-->login.html文件内容return render(request,"login.html")  # 默认输出登录页面
View Code

访问url: http://127.0.0.1:8000/login/

输入一个错误的密码,点击提交

页面输出,用户名和密码错误

那么,render就是干了这些事情。

 

总结:

对于Django而言,一次请求必须返回一个HttpResponse(字符串)

request对象,存放了请求路径,请求方式,请求数据,比如GET和POST

所以对于视图函数而言,最关心的部分就是request和HttpResponse

一次请求,必有一次响应。如果没有响应,就会报错

 

范围url: http://127.0.0.1:8000/index/

在视图函数中,render是渲染的意思。那么它是如何工作的呢?

1 按着settings-TEMPLATES-DIRS路径找指定文件
2 读取文件所有字符串
3 渲染: 检查字符串中是否有{{变量}}    ,if 没有找到:HttpResponse(文件字符串)else找到 {{变量}},用render第三个参数中的对应值进行相应替换(如果没有找到对应值,{{变量}}替换为空)HttpResponse(替换后的文件字符串)

那么渲染的过程,是在后端完成的。不是前端完成的。
看html代码,就知道了。浏览器根本不认识{{变量}},它只能识别html,css,js

注意:如果模板里面,写了{{变量}} 。但是render没传,那么页面中{{变量}} 会被替换为空。

如果模板里面,写了{{ }} 。变量名没写,那么页面报错

 

如果render传了变量,但是模板里{{变量}} ,变量名写错了,页面中{{变量}} 也会被替换为空。

 

 

思考:如何点击时间的时候,变成红色?

 直接加行内样式?不对,它是点击的时候,才变成红色。

需要引入jquery来做,修改index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<h4>当前时间: <span class="time">{{ ctime }}</span></h4>
<script type="application/javascript">$(function(){$('.time').click(function () {$(this).css("color","red")})});
</script>
</body>
</html>
View Code

访问url: http://127.0.0.1:8000/index/

点击时间,就会变红

但是,线上服务器不能这么干?为什么呢?因为如果一旦jquery访问链接失效。那么整个网站就崩溃了!

所以这种文件,还是需要放到自己的服务器上,才行!

那好办呀,将jquery.min.js放到templates目录。

编辑index.html,直接引入jquery.min.js文件。

<script src="jquery.min.js"></script>

再次访问页面,怎么点击都没效果,查看控制台,点击网络部分,发现它是404了!

不要以为templates下的文件,可以随便访问。太天真了!

浏览器是不能直接访问templates下的文件,需要Django找到静态文件才行!

在根目录,创建static目录,它是专门存放静态文件的。
将js文件进去。项目目录结构如下:

mysite/
├── blog
│   ├── admin.py
│   ├── apps.py
│   ├── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── manage.py
├── mysite
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── static
│   └── jquery.min.js
└── templates├── index.html└── login.html

修改settings.py,最后一行添加,注意:STATIC_URL和它是成对使用的。

STATIC_URL = '/static/'
STATICFILES_DIRS = (os.path.join(BASE_DIR,"static"),
)

STATIC_URL参数,表示别名。

STATICFILES_DIRS表示物理路径。

STATIC_URL代指STATICFILES_DIRS定义的路径。
修改index.html,更改src属性

<script src="/static/jquery.min.js"></script>

注意:这里面的/static/ 是别名,它代指的是物理路径

重新访问页面,再次点击,就会变红。

 

因为diango利用前缀STATIC_URL的具体内容,来映射STATICFILES_DIRS, 那么它就可以找到具体的文件。

比如前台页面的静态资源路径,一般都是写死了,可能涉及到几百个网页。网站在运营过程中,难免后台服务器,需要做迁移工作,可能和之前的存储路径不一样的。这个时候,让前端去改几百个网页,是一个很繁杂的工作。现在只需要修改STATIC_URL,就可以完美解决这个问题!!!

 

 未完待续...

 

转载于:https://www.cnblogs.com/xiao987334176/p/9210620.html

这篇关于python 全栈开发,Day67(Django简介)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/283144

相关文章

Python运行中频繁出现Restart提示的解决办法

《Python运行中频繁出现Restart提示的解决办法》在编程的世界里,遇到各种奇怪的问题是家常便饭,但是,当你的Python程序在运行过程中频繁出现“Restart”提示时,这可能不仅仅是令人头疼... 目录问题描述代码示例无限循环递归调用内存泄漏解决方案1. 检查代码逻辑无限循环递归调用内存泄漏2.

Python中判断对象是否为空的方法

《Python中判断对象是否为空的方法》在Python开发中,判断对象是否为“空”是高频操作,但看似简单的需求却暗藏玄机,从None到空容器,从零值到自定义对象的“假值”状态,不同场景下的“空”需要精... 目录一、python中的“空”值体系二、精准判定方法对比三、常见误区解析四、进阶处理技巧五、性能优化

使用Python构建一个Hexo博客发布工具

《使用Python构建一个Hexo博客发布工具》虽然Hexo的命令行工具非常强大,但对于日常的博客撰写和发布过程,我总觉得缺少一个直观的图形界面来简化操作,下面我们就来看看如何使用Python构建一个... 目录引言Hexo博客系统简介设计需求技术选择代码实现主框架界面设计核心功能实现1. 发布文章2. 加

python logging模块详解及其日志定时清理方式

《pythonlogging模块详解及其日志定时清理方式》:本文主要介绍pythonlogging模块详解及其日志定时清理方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录python logging模块及日志定时清理1.创建logger对象2.logging.basicCo

Python如何自动生成环境依赖包requirements

《Python如何自动生成环境依赖包requirements》:本文主要介绍Python如何自动生成环境依赖包requirements问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑... 目录生成当前 python 环境 安装的所有依赖包1、命令2、常见问题只生成当前 项目 的所有依赖包1、

如何将Python彻底卸载的三种方法

《如何将Python彻底卸载的三种方法》通常我们在一些软件的使用上有碰壁,第一反应就是卸载重装,所以有小伙伴就问我Python怎么卸载才能彻底卸载干净,今天这篇文章,小编就来教大家如何彻底卸载Pyth... 目录软件卸载①方法:②方法:③方法:清理相关文件夹软件卸载①方法:首先,在安装python时,下

python uv包管理小结

《pythonuv包管理小结》uv是一个高性能的Python包管理工具,它不仅能够高效地处理包管理和依赖解析,还提供了对Python版本管理的支持,本文主要介绍了pythonuv包管理小结,具有一... 目录安装 uv使用 uv 管理 python 版本安装指定版本的 Python查看已安装的 Python

使用Python开发一个带EPUB转换功能的Markdown编辑器

《使用Python开发一个带EPUB转换功能的Markdown编辑器》Markdown因其简单易用和强大的格式支持,成为了写作者、开发者及内容创作者的首选格式,本文将通过Python开发一个Markd... 目录应用概览代码结构与核心组件1. 初始化与布局 (__init__)2. 工具栏 (setup_t

Python中局部变量和全局变量举例详解

《Python中局部变量和全局变量举例详解》:本文主要介绍如何通过一个简单的Python代码示例来解释命名空间和作用域的概念,它详细说明了内置名称、全局名称、局部名称以及它们之间的查找顺序,文中通... 目录引入例子拆解源码运行结果如下图代码解析 python3命名空间和作用域命名空间命名空间查找顺序命名空

Python如何将大TXT文件分割成4KB小文件

《Python如何将大TXT文件分割成4KB小文件》处理大文本文件是程序员经常遇到的挑战,特别是当我们需要把一个几百MB甚至几个GB的TXT文件分割成小块时,下面我们来聊聊如何用Python自动完成这... 目录为什么需要分割TXT文件基础版:按行分割进阶版:精确控制文件大小完美解决方案:支持UTF-8编码