Python三大主流后端框架
"""
Django
特点:大而全,自带的功能特别多
缺点:有时候过于笨重
flask
特点:小而精,自带的功能特别少
但是第三方模块非常的多,如果将flask第三方的模块全部加起来完全可以盖过Django
缺点:比较依赖第三方的开发者(兼容性问题)
tornado
特点:异步非阻塞,支持高并发
设置可以开发游戏服务器
"""
a:socket部分
b:路由与视图函数对应关系(路由匹配)
c:模板语法
Django
a:用的别人的 wsgiref模块
b:自己写的
c:自己写的
flask
a:别人的 werczeug(内部还是wsgiref模块)
b:自己写的
c:别人写的(jinja2)
tornado
a、b、c都是自己写的
Django简介
需要注意的问题
如何让你的计算机能够正常的启动Django项目
1、计算机的名称不能有中文
右键电脑,点属性查看
2、一个pycharm窗口只开一个项目,不要有文件夹一层套层
3、项目里面的所有的文件也尽量不要出现中文
4、Python解释器尽量使用3.4-3.6之间的版本
(如果启动项目报错,找到源码中的152行,删掉最后一个逗号)
C:\Python38\Lib\site-packages\django\contrib\admin\widgets.py
Django版本问题
django3.X:自带异步功能
django2.X:默认不支持异步
django1.X:默认不支持异步
我这里使用1.11.11版本
Django安装
"""该命令基于已经配置好Python环境的前提下"""
pip3 intall django==1.11.11
如果已经安装了其他版本,无需自己卸载
直接重新安装,会自动卸载安装新的
安装的时候如果报错,看看是不是timeout,如果是,那么只是网络波动,重新安装即可
安装完成后再窗口输入django-admin命令,有一竖条的结果展示出来就安装成功了
配置文件夹template的文件路径
在使用命令行创建好Django项目后,要创建一个template文件夹(用来存放HTML页面),然后还需要在配置文件settings中配置文件路径,pycharm中创建的Django项目不用管这个
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',
],
},
},
]
创建app时要记得在配置文件settings中注册app
在app创建成功后,一定要在配置文件settings中注册app
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# 每创建一个app就要注册一次,可以写全称也可以写简写,app01表示你创建的app的名字
'app01.apps.App01Config', # 写全
'app01' # 简写
]
Django的基本操作
命令行创建Django项目
# 1、创建Django项目
# 创建时可以切换到D盘,避免占用C盘空间
输入命令 django-admin startproject 项目的名字(如django_project)
创建成功后可以在D盘中看的文件夹django_project:
django_project
manage.py
django_project
__init__.py
settings.py
urls.py
wsgi.py
# 2、启动Django项目
# 要先在命令行中切换到项目目录下
cd 项目名(如django_project)
python3 manage.py runserver IP:PORT
"""IP:PORT可以不写,不写就默认在8000端口起服务"""
在浏览器输入127.0.0.1:8000查看是否返回页面
# 3、APP创建应用
python3 manage.py startapp 应用名(如app)
Django应用的概念
django框架相当于是一所大学,应用相当于是大学里面的各个学院
大学相当于是个空壳子 负责提供环境
学院才是一个个真正具备特定功能的集合
eg:
使用django写一个淘宝,淘宝里面有很多功能模块
我们应该先创建一个空的django项目然后根据功能的不同创建不同的应用
django项目
应用名01(user) 用户相关业务
应用名02(order) 订单相关业务
应用名03(goods) 产品相关业务
应用名04(backend) 后台相关业务
主要文件介绍
-django_project文件夹名称
--django_project同名文件夹
----settings.py 项目配置文件
----urls.py 总路由层
--manage.py 项目入口文件
--db.sqlite3 运行项目后自动创建(django自带的小型数据库)
--应用文件夹 通过命令创建(可以创建任意个数)
----migrations文件夹 存储数据迁移记录
----admin.py django提供的后台管理
----apps.py 用于配置文件的应用注册(创建的应用都需要去配置文件中注册)
----models.py 模型层(与数据库相关)
----views.py 视图层(编写当前应用核心业务逻辑代码)
----tests.py 自带的测试文件
settings配置文件介绍
# 当前项目的路径
BASE_DIR
# 上线之后把True改为False
DEBUG
# 允许访问的主机,上线之后可以写'*'
ALLOWED_HOSTS
# 注册的app
INSTALLED_APPS
# Django中间件
MIDDLEWARE
# HTML文件存放路径配置
TEMPLATES
# 项目指定的数据库(可以改别的数据库)
DATABASES
# 访问静态文件的令牌
STATIC_URL
Django小白必会的三板斧
使用之前记得导入
from django.shortcuts import render, HttpResponse, redirect
HttpResponse
返回字符串
return HttpResponse('你好啊 Django')
render
返回HTML页面,第一个参数要填request
return render(request, 'html_file.html')
render的两种传值方式
def html_file(request):
# 返回HTML页面,第一个参数要填request
user_info = {'username': 11223344, 'password': 123}
# 第一种传值方式:更加精确,节省资源
return render(request, 'html_file.html', {'name': 'liu', 'age': 15, 'user_info': user_info})
# 第二种传值方式:当你要传的值特别多的时候
"""locals会将当前名称空间中的所有变量名都传个HTML页面"""
return render(request, 'html_file.html', locals())
redirect
重定向,跳转到相应的网页,如果是自己写的网页则只用写一个后缀就可以了如(return redirect('/string/'))
return redirect('https://www.mmzztt.com')
写在app的views文件中
from django.shortcuts import render, HttpResponse, redirect
# Create your views here.
def string(request):
"""
:param request:请求相关的所有的数据 对象 ,比之前的env功能更强大
:return:
"""
# 返回字符串
return HttpResponse('你好啊 Django')
def html_file(request):
# 返回HTML页面,第一个参数要填request
return render(request, 'html_file.html')
def redirect_url(request):
# 重定向,跳转到相应的网页,如果是自己写的网页则只用写一个后缀就可以了如(return redirect('/string/'))
return redirect('https://www.mmzztt.com')
写在urls的文件中
# Django自动导入的
from django.conf.urls import url
from django.contrib import admin
# 手动导入创建的app的views文件
from app01 import views
urlpatterns = [
# Django自带的一个后台管理
url(r'^admin/', admin.site.urls),
# 自己写的路由与视图函数的对应关系,获取用户输入的路由,跳转对应的视图
url(r'string/', views.string),
url(r'html/', views.html_file),
url(r'mmzztt/', views.redirect_url)
]
配置静态文件
静态文件介绍及创建
前端已经写好了的,能够直接使用的文件
网站写好的js文件
网站写好的css文件
网站用到的图片文件
第三方前端框架(如:bootstrap)
# 我们将HTML文件默认放在templates文件夹下
# 网站使用的静态文件默认放在static文件夹下
# Django默认不会帮我们创建static文件夹,需要我们自己手动创建
一般情况下我们会将static文件夹内做进一步的划分处理
static文件夹
js文件夹
css文件夹
img文件夹
其他第三方框架(可以创一个文件夹也可以不创)
如何访问静态文件
"""
在浏览器中输入URL能够看到对应的资源
是因为后端提前开设了该资源的接口
如果访问不到资源,说明没有开设该资源的接口
"""
例如,在templates文件夹中的HTML页面导入bootstrap框架:<link rel="stylesheet" href="../static/bootstrap-3.4.1/css/bootstrap.min.css">
但是运行后发现导入的框架不起作用,这是因为没有给他开设接口,HTML文件访问不到
"""要解决上述问题就要"""
# 1、在配置文件settings中手动写入配置(全部都要,包括变量名,不是填列表)
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static')
]
# 2、并且还要在文件前加入访问静态文件的令牌
STATIC_URL = '/static/'
/static/就是访问静态文件的令牌
<link rel="stylesheet" href="/static/bootstrap-3.4.1/css/bootstrap.min.css">
"""
注意,static不是我们创建的static文件夹,而是访问令牌,访问令牌是可以改变的,例如改为/xxx/,那么导入的时候就要写成
"""
<link rel="stylesheet" href="/xxx/bootstrap-3.4.1/css/bootstrap.min.css">
# 这是导入格式,导入js文件同样的
<script src="/令牌/文件路径"></script>
<link rel="stylesheet" href="/令牌/文件路径">
# 当有多个静态文件夹时
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static1'),
os.path.join(BASE_DIR, 'static2'),
os.path.join(BASE_DIR, 'static3')
]
当你的导入路径开头有静态访问令牌时,会把令牌后面的路径按顺序,一个个的跟STATICFILES_DIRS列表中写入的路径进行对比,直到对上,如果一直没有对上,就会返回错误信息
动态文件解析(HTML页面动态的获取令牌)
// 当配置文件STATIC_URL = '/static/'中的令牌static变动时,导入静态文件的HTML页面都要跟着改路径前面的令牌,实在是太不人性化,动态文件解析完美解决了该问题
{% load static %}
<link rel="stylesheet" href="{% static 'bootstrap-3.4.1/css/bootstrap.min.css' %}">
<script src="{% static 'bootstrap-3.4.1/js/bootstrap.min.js' %}"></script>
谷歌浏览器清除缓存
# 1、打开检查
# 2、点击设置 settings
# 3、偏好设置 preferences
# 4、网络 network
# 5、停用缓存 Disable cache
request对象方法初识
form表单提交数据
<form action="" method="post">
action参数
1、不写:默认朝当前所在的url提交数据
2、全写:写那传那
3、只写后缀:/login/,跟用户输入后缀是一样的
method参数
get或者不写都是get请求,数据放在?后面
post:post请求
# 当我们向Django提交post请求的时候,需要到配置文件中注释一行代码
# Django中间件
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 前期要发送post请求要注释下面这条代码,否则会报403,权限不足
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
request对象方法之method
def login(request):
# method方法返回的是请求方式,并且是大写字符串的形式
request.method # POST
request对象方法之POST/GET
def login(request):
if request.method == 'POST':
# POST方法返回接收到的post请求
post_list = request.POST
elif request.method == 'GET':
# GET方法返回接收到的get请求
get_list = request.GET
get与getlist
# get请求和post请求都是用get和getlist取值
"""{'username': ['阿斯蒂芬'], 'password': ['asdf'], 'hobby': ['111', '222', '333']}"""
# get只能获取列表中最后一个元素
# getlist可以获取完整的列表
def login(request):
"""
get请求好post请求应该有不同的处理机制
:param request: 请求相关的数据对象,里面有很多简易的方法
:return:
"""
# method方法返回的是请求方式,并且是大写字符串的形式
if request.method == 'POST':
# POST方法返回接收到的post请求
# GET方法返回接收到的get请求
post_list = request.POST
print(post_list) # <QueryDict: {'username': ['阿斯蒂芬'], 'password': ['asdf'], 'hobby': ['111', '222', '333']}>
# .get方法只能获得列表中最后一个元素
hobby1 = post_list.get('hobby')
print(hobby1) # 333
# .getlist可以获得完整的列表
hobby2 = post_list.getlist('hobby')
print(hobby2) # ['111', '222', '333']
username = post_list.getlist('username')
print(username)
return HttpResponse('提交了post请求')
return render(request, 'login.html')
pycharm链接数据库(mysql)
注意要提前创建好库
Django链接MySQL
# Django默认使用的是sqlite3,但是不好用,换成MySQL,在配置文件中直接注释掉这段,重新写
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
第一步:更改配置文件
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
# 库的名字
'NAME': 'user_info',
# 账号
'USER': 'root',
# 密码
'PASSWORD': '123',
# ip
'HOST': '127.0.0.1',
# 端口
'PORT': 3306,
# 字符编码
'CHARSET': 'utf8'
}
}
第二步:代码申明
"""
Django默认使用的是mysqldb模块链接MySQL
但是该模块的兼容性不好,需要手动改为用pymysql模块链接
"""
# 在Django项目下的__init__.py文件或者app下的__init__.py文件下写代码
import pymysql
# 用pymysql模块替换mysqldb模块
pymysql.install_as_MySQLdb()
Django ORM(Django操作MySQL)
ORM介绍
"""
ORM:对象关系映射
作用:能够让一个不会SQL语句的小白能通过Python代码,面向对象的代码简单快捷的操作数据库
不足之处:封装程度太高,有时候SQL语句的效率偏低,需要你自己写SQL语句
类 表
对象 记录
对象属性 记录某个字段对应的值
"""
ORM使用
# 应用文件的下的models.py文件中写ORM
创建表
1、先在models文件中写一个类
class User(models.Model):
# 由于一张表中必须有一个主键字段,并且一般都加id字段
# 所以ORM当你没有定义主键字段的时候,他会帮你自动创建名为id的主键字段
# 对应的SQL语句:id int primary_key auto_increment
id = models.AutoField(primary_key=True, verbose_name='主键')
# 注意:CharField方法必须指定max_length参数,不指定就报错
# 对应的SQL语句:username varchar(32)
username = models.CharField(max_length=32, verbose_name='用户名')
# verbose_name参数是对该字段的解释,每个字段都有这个参数
# 对应的SQL语句:password int
password = models.IntegerField(verbose_name='密码')
2、数据库迁移命令
# 点击pycharm中的Terminal打开终端,输入命令
# 1、将操作记录记录到migrations文件夹中,并生成一个文件
python3 manage.py makemigrations
# 2、将操作同步到数据库当中
python3 manage.py migrate
"""
在你第一次同步操作到数据库当中时,Django会默认创建很多的表,先不用理会
其中第一个表就是刚刚通过代码创建的表
表的的名字是你应用的名字加下划线再加类的名字组合成的,是为了防止不同应用表名相同起冲突
"""
"""只要你改了models文件中跟数据库相关的代码,就必须要重新输入上面两行代码"""
字段的增删改查
# 增
# 第一种方法
当表中有数据时,直接"age = models.IntegerField(verbose_name='年龄')"增加字段,终端输入命令"python3 manage.py makemigrations",终端会给你返回以下提示:
You are trying to add a non-nullable field 'age' to user without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Quit, and let me add a default in models.py
"""
您正在尝试添加一个非空字段'年龄'用户没有默认值;我们不能这样做(数据库需要一些东西来填充现有的行)。
请选择修复:
1)现在提供一个一次性的默认值(将在该列的空值的所有现有行上设置)
2)退出,让我在models.py中添加一个默认值
"""
Select an option:
在终端输入:1
按回车后再输入你要给新增的字段给的默认值,回车后就可以增加字段了
# 第二种方法:让字段可以为空
info = models.CharField(max_length=32,verbose_name='个人简介',null=True)
# 第三种方法:为字段设置默认值
hobby = models.CharField(max_length=32,verbose_name='兴趣爱好',default='默认值')
# 删
直接在models文件中把字段注释,再运行那两行命令
"""注意:删除字段后,该字段的数据也会消失,在写代码的时候一定一定要细心,不要注释不该注释的"""
# 改
直接在models文件中修改字段属性即可
# 查
肉眼可见
数据的增删改查
查
查单个数据
# 查找User表格中username字段的数据为Jason的所有数据,这所有的数据就是一个对象
res = models.User.objects.filter(username='jason')
# 类似的SQL语句
select * from User where username='jason'
"""
返回值可以暂时看成是列表套对象的格式 [对象数据1,对象数据2,...]
它支持索引取值、切片操作,但是不支持负数索引
但是对剑是用.first()的方法取值
user_obj = models.User.objects.filter(username=username).first()
"""
filter括号内可以携带多个参数,参数与参数之间默认是and关系
filter类似于where
"""简单的登录验证功能"""
from app01 import models
def login(request):
# 判断是否是一个post请求
if request.method == 'POST':
# 获取用户名
username = request.POST.get('username')
# 获取密码,返回值是字符串形式
password = request.POST.get('password')
# User是models中创建的类名
user_obj = models.User.objects.filter(username=username).first()
if user_obj:
if password == user_obj.password:
return HttpResponse('登录成功')
return HttpResponse('密码错误')
return HttpResponse('账号不存在')
return render(request, 'login.html')
查所有数据
# 查看用户的所有数据
# 方法一:不推荐使用,语义不明
models.User.objects.filter()
# 方法二:all 推荐使用,语义明确
models.User.objects.all()
"""代码实例"""
# 用户数据展示功能
def userlist(request):
# 返回所有数据
user_query = models.User.objects.all()
return render(request, 'userlist.html', locals())
增
"""添加数据,username和password的数据为'liu'、'123'"""
# 第一种增加数据方法:create
models.User.objects.create(username='liu', password='123')
# 返回值就是当前被创建的对象本身
# 类似SQL语句
insert into t1 values(1,'liu','123');
# 第二种增加数据的方法:利用对象的保存方法
# 在User类中创建一个对象
user_obj = models.User(username='liu', password='123')
# save方法:保存数据
user_obj.save()
"""简陋的注册功能"""
def reg(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
# 添加数据的第一种方法
# models.User.objects.create(username=username, password=password)
# 添加数据的第二种方法
user_obj = models.User(username=username, password=password)
user_obj.save()
return HttpResponse('注册成功')
return render(request, 'reg.html')
改
# 修改数据
"""把id字段为1的username数据和password数据改为'liu'、'123'"""
# 第一种方法:update
# 将filter查询出来的列表中所有对象数据更新(批量操作)
models.User.objects.filter(id=1).update(username='liu',password='123')
# 第二种方法:利用对象的方法
# 该方法针只对这一个对象进行操作,但是效率非常低,从头到尾把数据全部更新一遍,无论是否被修改
user_obj.username = 'liu'
user_obj.password = '123'
user_obj.save()
"""代码实例"""
# 编辑功能
def edit_user(request):
user_id = request.GET.get('user_id')
user_obj = models.User.objects.filter(id=user_id).first()
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
# 修改数据
# 第一种方法:update 将filter查询出来的列表中所有对象数据更新(批量操作)
# models.User.objects.filter(id=user_id).update(username=username, password=password)
# 第二种方法:利用对象的方法
# 该方法针只对这一个对象进行操作,但是效率非常低,从头到尾把数据全部更新一遍,无论是否被修改
user_obj.username = username
user_obj.password = password
user_obj.save()
return redirect('/userlist.html/')
return render(request, 'edit_user.html', locals())
删
# 删除id为1的所有数据
# delete方法
models.User.objects.filter(id=1).delete()
"""代码实例"""
# 删除功能
def delete_user(request):
delete_id = request.GET.get('user_id')
# delete方法:删除数据
models.User.objects.filter(id=delete_id).delete()
return redirect('/userlist/')
上述代码操作的主要前端页面:userlist.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
{% load static %}
<link rel="stylesheet" href="{% static 'bootstrap-3.4.1/css/bootstrap.min.css' %}">
<script src="{% static 'bootstrap-3.4.1/js/bootstrap.min.js' %}"></script>
<title>Title</title>
</head>
<body>
<h1 class="text-center">
用户数据
</h1>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>ID</th>
<th>账号</th>
<th>密码</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for user_obj in user_query %}
<tr>
<td>{{ user_obj.id }}</td>
<td>{{ user_obj.username }}</td>
<td>{{ user_obj.password }}</td>
<td>
<a href="/edit_user/?user_id={{ user_obj.id }}" class="btn btn-primary btn-xs">编辑</a>
<a href="/delete_user/?user_id={{ user_obj.id }}" class="btn btn-danger btn-xs">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>
ORM创建表关系
"""表关系"""
# 一对多
# 多对多
# 一对一
"""具体实例"""
出版社、作者简介、图书、作者详细信息
# 作者与图书是一对多的关系,图书是多,所以外键在图书表
# 出版社与图书是多对多关系,在mysql中需要额外创建一个表来关联两者的关系
# 作者简介与作者详情是一对一关系,外键建在使用频繁的那个表上
class Book(models.Model):
# 字符串字段
title = models.CharField(max_length=32, verbose_name='书名')
# 小数字段,最多8个,小数占两个
price = models.DecimalField(max_digits=8, decimal_places=2, verbose_name='价格')
# 建立一对多外键字段,图书与作者是一对多的关系,但是图书是多的一方,所以外键建在图书表中
# 默认与主键字段做外键关联
author = models.ForeignKey(to='Author')
# 建立多对多,图书与出版社是多对多关系,外键字段在任意一方即可,但是建议在使用频率高的一方建
# authors是一个虚拟字段,主要用来告诉ORM图书与出版社是多对多关系,让ORM自动帮你创建第三张表
authors = models.ManyToManyField(to='Publish')
class Publish(models.Model):
# 字符串字段
name = models.CharField(max_length=16, verbose_name='出版社名字')
# 字符串字段
addr = models.CharField(max_length=32, verbose_name='出版社地址')
class Author(models.Model):
# 字符串字段
name = models.CharField(max_length=8, verbose_name='作者名字')
# 数值字段
age = models.IntegerField(verbose_name='作者年龄')
# 作者简介与作者详情是一对一关系,字段创建在任意一方都可以,但是建议创建在使用频率高的一方
author_details = models.OneToOneField(to='AuthorDetails')
class AuthorDetails(models.Model):
# 电话用int可能存不下,所以用binint存,或者直接用字符类型存
phone = models.BigIntegerField(verbose_name='电话号码')
# 字符串字段
addr = models.CharField(max_length=32, verbose_name='作者地址')
# 一对多,建立在多的一方
# 默认与主键字段做外键关联
字段名 = models.ForeignKey(to='关联的表')
# 多对多,建议在使用频率高的一方建
# 这是一个虚拟字段,主要用来告诉ORM多对多关系,让ORM自动帮你创建第三张表
字段名 = models.ManyToManyField(to='关联的表')
# 一对一,建议创建在使用频率高的一方
字段名 = models.OneToOneField(to='关联的表')
"""ForeignKey和OneToOneField在创建字段时会自动在字段名后面加上_id的后缀"""
# 在Django1.x中表关系都是自动联级更新的