Django(Web应用,Django框架)
Web应用的简介
Web应用程序是什么?
Web应用程序是一种可以通过Web访问的应用程序,也就是说只需要一个浏览器即可,不需要其他软件了。
应用程序有两种模式:C/S、B/S
Django就是开发的B/S应用程序,所以,我们就认为浏览器就是我们的客户端,Django框架就是服务端。
Web应用程序的优点:
1. 只需要一个浏览器即可,不再需要安装其他的应用软件。
2. 节省用户的资源空间
3. 它们不需要更新,是因为服务端只要一更新版本,会直接影响客户端的更新
4. 跨平台使用
Web应用程序的缺点:
一旦Web应用程序的服务端宕机,直接影响客户端的正常访问!!!
Web框架:
框架的意思就是别人提前写好的,我们只需要按照人家的要求在固定的位置写好固定的代码。
手撸Web框架
推导框架的演变,代码无需掌握,重点看思路。
Web应用程序主要就是B/S架构的,浏览器就是客户端,只要现在开发出一个服务端即可。
HTTP协议的相关知识:
四大特性:
基于请求和响应
基于TCP协议之上的应用层协议
无状态
短连接/长连接
请求数据格式:
请求首行(请求方式、协议版本号)
请求头
/r/n
请求体
响应数据格式:
响应首行(响应状态码)
响应头
/r/n
响应体
响应状态码:
1xx 、2xx 、3xx 、4xx 、5xx
当我们手写Web框架会出现这种页面,是因为服务端发送的数据不符合HTTP协议规定的格式
代码:服务端
import socket sever = socket.socket() sever.bind(('127.0.0.1',8000)) sever.listen(3) print('开始接收数据') while True: conn,addr = sever.accept() data = conn.recv(1024) print(data.decode('utf8')) # 使用流式协议规范发送的数据格式 conn.send(b'HTTP/1.1 200 ok \r\n\r\n') conn.send(b'hello') conn.close()
结果:
网页显示:
问题:怎样做到在浏览器的地址栏中写什么就显示什么?
思路:
1. 在后端肯定是要知道我们在浏览器输入了什后缀
2. 进行判断,判断是什么后缀就返回什么
浏览器每次朝后端发起请求的时候,都会多一次:/favicon.ico(图标地址),可以先忽略。
存在的问题:
1. socket部分我们每次都要书写(要写重复代码)
2. 我们需要自己来处理HTTP格式的数据,自己做切分,自己来取值等比较麻烦
3. 并发问题没有解决
借助于wsgiref模块(内置模块,直接使用)
from wsgiref.simple_server import make_server
解决了socket部分,不需要我们自己写了,在wsgiref模块里人家帮我们写了。
它解决了并发问题WSGIServer类------>wsgiref------>它能够解决的并发量不高----->本地使用wsgiref服务器--------------->代码上线之后,就不是有它----------->uwsgi服务器(它支持的并发量更高)
代码上线之后会使用 Nginx + uwsgi
代码:
from wsgiref.simple_server import make_server def run(env,response): # env:类似于request,客户端每次发起请求的时候,所携带的数据都在这个里 # response:后端给浏览器返回的数据 print(env) # 将HTTP格式的数据都封装到了大字典里去了 response("200 OK",[]) current_path = env.get('PATH_INFO') # 进行判断 if current_path == '/index': return [b'index'] # return: 返回给浏览器查看的 elif current_path == '/login': return [b'login'] else: return [b'404 error'] if __name__ == '__main__': server = make_server(host='127.0.0.1',port=8000,app=run) #run是个函数名(在django中用的就是函数名) # app=run:只要有客户度发过去请求,那么就会把处理的请求交给run这个函数来处理 #启动服务端 server.serve_forever()
结果:
改进版:
"""
views.py----------------->视图文件--------->主要就是写后端的逻辑的
urls.py------------------>路由文件(后缀)---------->路由与视图函数的对应关系
templates---------------->专门用来存储html文件的
"""
以后我们要想增加一个后缀,只需要在urls.py中写一个路由和在views.py中写一个视图函数即可。
Django框架的学习
Django是python中使用最多的一个主流框架
python中的主流框架:
Django:
主要用来开发Web项目的,比较笨重,一般小型项目不怎么使用它,大而全
flask:
是一个比较轻量级的框架,主要依赖于第三方的模块,不断的安装第三方模块,小而精。
tornado:
异步非阻塞,比较擅长解决高并发问题
版本问题:
1.X(老项目) 2.X(新项目) 3.X(新版本),1.x和2.x本质上差别不是很大,但是也有区别。
在drf中,都要使用2.x以上版本,drf这个框架要求Django的版本必须2.x以上
注意事项:
1. 你的项目名称和应用名称以及其他文件的名称都要使用英文的,坚决不能够使用中文的
2. 你的计算机名称最后都使用英文的
3. 一个pycharm窗口只打开一个django项目,不能够一个窗口打开很多个django项目
如何使用Django:
1. 安装Django
pip install Django == 1.11
Django的版本要和解释器的版本要匹配:
Django2.x版本------------>解释器的版本最好3.6以上
如何验证Django是否安装成功:
在cmd中输入:django-admin。如果有输出内容就说明安装成功
创建项目:
1. 命令行创建:
可以先切换路径,切换到你想把Django项目放到的路径里
命令:django-admin startproject 项目名
2. pycharm创建
File下的New Project 中的django
命令行与pycharm创建的区别:
命令行创建不会自动有templatew文件夹,需要自己手动创建而pycharm会自动创建并且还会自动在配置文件中配置对应的路径。也就意味着用命令行创建Django项目的不单单要创建templates文件夹还需要去配置文件中配置路径。
启动项目:
1. 命令行启动(cmd)
先把路径切到manage.py文件所在路径,然后再输入:python36 manage.py runserver
如图:
项目启动起来之后,会监听:http://127.0.0.1:8000/
默认端口号是:8000
如何修改端口号:python36 manage.py runserver 127.0.0.1 8001
2. pycharm启动:点击启动按钮
访问项目:http://127.0.0.1:8000/
结果:
创建应用:
1. 命令行创建
python manage.py startapp [app_label]
python manage.py startspp app01
2. pycharm 创建
当把应用创建出来之后,紧接着要做的一件事情就是:注册应用
在配置文件中注册应用,这个应用才生效
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01.apps.App01Config', # 全称 'app01', # 简称 ]
主要文件介绍
myfirst_dj # 项目名称
app01 # 应用名称
migrations # 这个是用来存储数据库迁移记录
__init__.py
admin.py # 和后台项目注册等相关
apps.py # 跟一些注册有关
models.py # 跟数据库打交道的 模型层----->MTV模型
tests.py # 测试文件
views.py # 视图文件,写一些后端逻辑
myfirst_dj
__init__.py
settings.py # 配置文件相关的
urls.py # 路由相关的
wsgi.py # 内部封装的wsgiref服务器,uwsgi服务器之后,这个文件就没用
db.sqlite3 # Django自带的小型数据库
manage.py # Django框架的入口文件
如图所示:
应用
Django主要开发的就是一款Web应用
Django框架类似于是一所大学(空壳子)
应用就是大学里面的二级学院(具备独立的功能模块)
一个应用就是一个独立的功能模块
比如:应用名一定要见名知意
user
order
address
cart...
小白必会三板斧
The view app01.views.index didn't return an HttpResponse object. It returned None instead.
return HttpResponse("OK") # 返回字符串的 return render(request, 'index.html') # 返回html文件的 return redirect('http://www.baidu.com') # 重定向
###############################自己创建的templates文件夹,要在配置文件注册################ TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], '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', ], }, }, ] ###############################自己创建的templates文件夹,要在配置文件注册################
端口后面要加路由,箭头所指的是我们已经设置好的路由,只有加了明确的路由才会去访问该路由所对应的内容
代码截图:
HttpResponse:返回字符串类型的数据
eg:
return HttpResponse("你好!")
render:返回html页面
eg:
return render(request,'myfirst.html')
redirect:重定向
eg:
return redirect('http://www.baidu.com') # 重定向:跳转到指定的页面
配置文件的介绍
在settings.py文件中:
1. 注册应用:
2.中间件:
红色框中的那句代码在Django连接数据库时需要注释掉,不然会报错。
3.根路由文件名:
4. Django连接MySQL数据库:
5. 访问静态文件的令牌:此处的static只是一个路径开头
静态文件的配置
以登录功能为例:
1. 先在urls文件中,添加登录路由与视图函数中登录函数的对应关系
2.在views文件中,编写登录函数,渲染登录页面
<form action="">
action参数的三种情况:
1. 什么都不写,就是朝当前地址提交数据
2. 要么全写:http://127.0.0.1:8000/login/?username=&password=
3. 只写后缀:http://127.0.0.1:8000/login/
初步的登录结果如图:
4. 接下来就是要向后端提交数据,要用POST请求方式,但是默认请求方式是GET,如下图所示:
点击链接会出现下面页面,是因为中间件中有一个文件需要注释掉(为了安全会报错)
需要注释掉,页面就不会报错了。
我们将html文件默认都放在templates文件夹下
我们将网站所使用的静态文件默认放在static文件夹下,需要手动创建这个文件夹。
静态文件:
网站使用的css文件
网站使用的js文件
网站使用的图片
网站使用的第三方库文件(jQuery、Bootstrap等)
我们还可以针对不同的功能对static文件夹里面的文件进行拆分
可以拆分为:
css
js
img
...
当我们导入内部的html页面样式文件时会出现,导入的样式文件并没有生效
文件路径并没有被找到,所以出现404错误
http://127.0.0.1:8000/static/bootstrap-3.4.1-dist/css/bootstrap.min.css,看起来是对的,该地址并没有被访问到。
# 你之前访问的地址都可以访问到,那是因为你在后端开设了可以访问的接口(路由)
# 之所以你现在访问不到刚才的地址,是因为你在后端没有开设这样的一个可访问的接口(路由)
# Django自动的帮我们写好了这样的接口
# 访问静态文件的令牌,以后你只要访问静态文件的路径,就要以/static/开头
需要做下面的修改:(静态文件)
在login.html文件中:将/前面的..去掉,要以/static开头
在settings.py文件中:需要添加STATICFILES_DIRS文件路径
各个static的关系如下图
动态文件分析:{% %}里面写路径
配置文件中:
结果如图:
request对象请求方法
request.method # 请求方式 GET POST print(request.POST) # <QueryDict: {'username': ['jason'], 'password': ['123']}> print(request.POST.get('username')) # jason print(request.GET) # <QueryDict: {'username': ['jason'], 'password': ['123']}> print(request.GET.get('username')) # jason
例子:
结果如图:
pycharm连接数据库
pycharm它也支持连接数据,Navicat连接数据库,大多数都是使用Navicat。
Django连接MySQL
默认情况下:
连接数据库:
连接MySQL数据的时候可能报错的解决办法:
解决bug的思路:
1. 就是print()
2. 看是否有日志
3. 看报错的信息去百度中搜索
4. 问问别人
1. 如果解释器版本导致的问题,直接改源码
def get_new_connection(self, conn_params): conn = Database.connect(**conn_params) conn.encoders[SafeText] = conn.encoders[six.text_type] # 先判断bytes是否存在于编码器中,如果在才执行操作 if bytes in conn.encoders: # 加上这句话 conn.encoders[SafeBytes] = conn.encoders[bytes] return conn
2. 解释器版本改为3.6的时候也会报错
Django的底层默认使用的是mysqldb模块,这个模块兼容性很差
# 我们还使用pymysql连接mysql,你要提前安装pymysql模块
报错信息:
解决方法:在项目的任意的__init__.py中加下面两行代码
import pymysql pymysql.install_as_MySQLdb() # 猴子补丁# 这两行代码的意思就是把底层的mysqldb模块换成pymysql
3. 除了使用mysqldb、pymysql之外还可以使用mysqlclient这个模块
你用了mysqlclient这个模块,就不用加上面那两句话了
mysqlclient安装的时候可能会报各种错误
Django中的ORM
ORM:对象映射模型
以后在Django中写根数据库相关的代码时候,就不用再写原生的SQL语句了,直接通过python代码来操作数据的增删改查。
orm的书写位置:在models.py中书写
概念:
表 >>>>> 类名
记录 >>>>> 对象
字段 >>>>> 属性
创建一张表:
from django.db import models # Create your models here. # 所有的类必须继承models.Model class User(models.Model): # 类名 # 在MySQL中: id int primary key auto_increment id = models.AutoField(primary_key=True) # username varchar(64) username = models.CharField(max_length=64) # password varchar(64) password = models.CharField(max_length=64)
如图所示:
类写完之后,一定要做数据库迁移,真正的在数据库中生成表:
python36 manage.py makemigrations # 它的作用是把数据库的迁移记录保存下来
python36 manage.py migrate # 才是真正的把数据表创建出来
如果前面有表已经创建了主键字段叫id,那么后面的表可以不用再创建id,也能生成id主键,但是要是要想设定aid为主键,就要自己在创建的表中设定
如图所示:
ORM增删改查字段
1如何做查询 select * from author where username = jack and password = 123
objects:小组件,里面封装了很多的方法
res=models.Author.objects.filter(name=username, password=password).all() # 是and查询
res=models.Author.objects.filter(name=username, password=password) # 是and查询
res=models.Author.objects.filter(name=username).filter(password=password)# 是and查询
res=models.Author.objects.filter(name=username, password=password).first() # 是and查询
res=models.Author.objects.create(name=username,password=password)
print(res) # <QuerySet [<Author: Author object>]> QuerySet对象以后可以点出来很多的方法
print(res) # Author object QuerySet对象以后可以点出来很多的方法
ORM的增删改成方法
1.查询
res=models.表名(类名).objects.all()[0]
res=models.表名(类名).objects.filter(username=username, password=password).all()
res = models.表名(类名).objects.first() # 去一条数据 # 判断,内部判断数据是否有,有人家在取0
# res如果查询出来的是一条,直接就是对象
# res它查询来的是多条,结果就是queryset对象 [对象,对象,对象]
# 如果你使用的all查询的,就算查询一条数据,结果也是queryset对象 [对象,对象,对象]
# 我们直接可以对queryset对象进行循环遍历
2. 增加
第一种方式:
res=models.表名(类名).objects.create(username='', password='')
'''增加数据的时候也有返回结果:就是当前插入成功的数据对象''' # 可不是影响的行数
res.username
res.password
第二种方式:
obj = models.表名(类名)(username='', password='')
obj.save()
3. 更新
第一种方式:
res=models.表名(类名).objects.update(username='', password='') # 全表更新
res=models.表名(类名).objects.filter().update(username='', password='')
'''返回的结果才是影响的行数'''
第二种方式:
# 先查询
user_obj = models.表名(类名).objects.first()
user_obj.username = username
user_obj.save()
4. 删除
models.表名(类名).objects.filter().delete() # 直接就删除了
"""删除的方式有两种类型"""
1. 物理删除:直接把数据从磁盘中删除,.delete()方式就是直接物理删除
2. 软删除: 软删除的意思是,不直接从硬盘中删数据,而是在表中在增加一个字段,一般叫is_delete
它的用法就是,正常的数据这个字段的值为0,如果你要删除这条记录,is_delete=1
# 每次删除的时候,只需要更新这个字段就可以了
软删除案例:
# 查询的时候怎么区分是正常数据还是已经被删除的数据?
models.表名(类名).objects.filter(is_delete=1).all() # is_delete=1:排除了被删除的数据
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)