-
Web应用
--- HTTP 请求 --->
浏览器 服务器
<--- HTTP 响应 ---静态内容:HTML页面、CSS、JavaScript、图像、音视频等 ---> Nginx
动态内容:需要通过程序自动生成的部分 ---> Python ---> 运行Python程序的服务器HTTP(s) ---> 超文本传输协议 ---> 使用了TCP提供的可靠传输服务
HTTP请求:请求行 / 请求头 / 空行 / 消息体
HTTP响应:响应行 / 响应头 / 空行 / 消息体 为什么用Python做后端开发?
~ 自动化运维 / 自动化测试 / 数据分析 / AI算法 / DevOps / SRE
~ 服务器端应用开发(Web后端开发)
---> App/网站的服务端代码编写(数据接口开发)
---> 用代码生成网站/App需要的动态内容(数据)
---> CGI / WSGI ---> PHP / ASP(C#) / JSP(Java)
~ Python也可以为作为服务器端应用开发的编程语言
~ 优点:开发效率极高(用很少的代码可以做很多的事情)
~ 缺点:执行效率不高(有很多公司更看重开发效率而不是执行效率)
~ Python有很多的框架专门用于服务器端应用开发
---> 使用框架可以减少重复代码和基础代码的编写
---> 程序员只需要专注于核心的业务逻辑代码的编写为什么选择Django框架?
---> 源于真实的CMS系统的项目
---> 生态圈非常繁荣 ---> 大部分功能都有成熟的解决方案-
创建Django项目和实施版本控制
~ pip3 install django==2.2.12 -i https://pypi.doubanio.com/simple
~ django-admin --version
~ django-admin startproject hellodjango
~ cd hellodjango创建虚拟环境
~ 方法一:virtualenv --python=/usr/bin/python3 venv
~ 方法二:python3 -m venv venv激活虚拟环境
~ source venv/bin/activate ---> macOS / Linux
~ "venv/Scripts/activate" ---> Windows重建项目依赖项:
~ 有依赖项清单:pip install -r requirements.txt
~ 如果没有依赖项清单:
- pip install django==2.2.12 mysqlclient django-redis requests
- pip freeze > requirements.txt~ git init
~ 根据需要添加版本控制忽略文件 ---> .gitginore ---> http://gitignore.io/
~ git add .
~ git commit -m '...'
~ Gitee上创建一个空的仓库
~ git remote add origin 仓库地址
~ git push -u origin master 创建Django应用
~ 一个Django项目中可以包含一个或多个Django应用
- 方法一:django-admin startapp 应用名
- 方法二:python manage.py startapp 应用名
~ settings.py ---> INSTALLED_APPS ---> 应用名
补充:Django框架使用了MTV架构模式 ---> MVC架构 ---> 数据和显示分离
同一组数据(模型)可以展示为不同的视图(HTML表格、ECharts图表、Excel报表)
同一个视图上也可以加载不同的模型进行渲染
M -----> 模型(数据)-----> M
V -----> 视图(数据的展示,呈现给用户看到的东西)-----> T
C -----> 控制器(连接数据和显示的桥梁,把模型和视图关联起来)-----> V
~ view.py ----> 视图函数 ----> 控制器
~ models.py ----> 模型
~ templates ----> 模板 ----> 视图
-
编写视图函数
~ views.py ---> 视图函数(接收来自浏览器的请求,给用户以响应)def show_index(request: HttpRequest):
return HttpResponse(content)
-
配置URL
~ 使用视图函数需要配置URL映射(请求的路由) ---> urls.py
~ URL(统一资源定位符) ---> 视图函数 ---> path函数path('hello/', show_index),
path('mcode/<str:tel>/', get_mobile_code),url(r'^mcode/(?P<tel>1[3-9]\d{9})/')
def get_mobile_code(request, tel):
pass 前端渲染和后端渲染
~ 真正的项目开发中,前端工程师会提供静态页面,如何让静态页面上呈现动态内容???
~ 方法一:前端渲染 ---> 在浏览器中完成渲染操作
前端通过Ajax请求获得后端提供的数据,通过JavaScript代码用数据渲染页面
~ 方法二:后端渲染 ---> 在服务器端用Python程序完成
把前端提供的静态页改造成模板页,把动态内容换成占位符,通过Python程序把动态内容填入模板页-
编写、配置、渲染模板页
<ul id="fruits">
{% for fruit in fruits %}
<li>{{ fruit.name }}: {{ fruit.price }}<a href="">×</a></li>
{% endfor %}
</ul>TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates'), ],
'APP_DIRS': True,
...
},
]render(request, 'index.html', {...}) ---> HttpResponse
-
运行Django项目
~ Django自带的测试服务器 ---> 不能用于生产环境
~ python manage.py runserverWeb Server Gateway Interface
Nginx / Apache --- wsgi ---> 实现了WSGI的服务器
支持WSGI协议的服务器就可以运行Python项目
~ uWSGI / Gunicorn Django框架中内置了ORM功能
~ ORM:对象关系映射 Object-Relational Mapping
Python程序 ----------------------> 关系型数据库
对象模型 -----对象持久化到数据库-----> 关系模型
对象模型 <----从数据库中获取数据------ 关系模型
class Subject(models.Model):
~ AutoField / IntegerField / DecimalField / DateTimeField
~ CharField / ImageField / FileField / BooleanField
~ OneToOneField / ForeignKey / ManyToManyField
~ 新增:Subject(...).save()
~ 查询:Subject.objects.all() / Subject.objects.filter() ---> QuerySet
~ 查询:Subject.objects.get() / Subject.objects.filter().first() ---> Subject
~ 排序:order_by()
~ 分页:[:] ---> Paginator ---> get_page() ---> Page
~ objects_list / has_prev / has_next / number
~ 分组和聚合:annotate() / aggregate()
~ 多条件组合筛选:Q对象
- Q & Q / Q | Q / ~Q
~ 更新:subject ---> subject.name = '...' ---> subject.save()
- F对象:queryset ---> update(字段=F('字段名') + 100)
~ 删除:subject ---> subject.delete()-
Django模型管理后台
~ python manage.py createsuperuser
~ 将模型注册到管理后台 ---> admin.py
admin.site.register(模型, 模型管理类)django-jet
返回JSON格式数据
JavaScript Object Notation ---> JavaScript创建对象的字面量语法 ---> 数据交换格式
Python字典 ---> JSON字符串
ujson ---> ultra json ---> C
~ 方法一:ujson.dumps(字典) ---> JSON字符串 ---> HttpResponse ---> application/json
~ 方法二:JsonResponse(字典) ---> JSON格式数据-
从请求中获取信息
HttpRequest
~ 获取请求参数:GET / POST / FILES / data
~ 获取请求路径: path / get_full_path_info()
~ 获取请求方法:method
~ 获取请求头:META / COOKIES
~ 判断是不是异步请求:is_ajax()
~ 获取带签名的cookie:get_signed_cookie()
HttpResponse
~ 响应状态码:status_code
~ 响应字符集:charset
~ 响应头:
- response['content-type']
- response['content-disposition']
~ set_cookie() / delete_cookie() / set_signed_cookie()用户跟踪:记住用户才能提供更好的更个性化的服务 ---> 浏览器本地存储
~ cookie
~ localStorage / sessionStorage
~ IndexDB -
表单和跨站请求伪造
CSRF ---> Cross Site Request Forgery ---> 跨站请求伪造/钓鱼网站Django框架通过在表单添加随机令牌的方式来解决CSRF问题
{% csrf_token %}
<input type="hidden" name="csrfmiddlewaretoken" value="...">
如果没有提供有效的随机令牌,Django框架会阻止表单提交,响应状态码403@csrf_exempt ---> 视图函数免除CSRF令牌的装饰器
数据库决不能放用户密码的原始数据 ---> 摘要/签名/指纹
hashlib ---> md5 / sha1 / sha256
sha256() ---> update(...) ---> hexdigest()
彩虹表攻击 ---> 反向查字典破解弱口令
如果你的网站允许用户使用弱口令,那么一定要通过加盐的方式把弱口令变成强口令再生成摘要
盐的值只有部署系统的管理员才知道(程序员和DBA都不知道)-
服务器如何保留用户状态 ---> 用户跟踪
服务器如果能记住用户,记住用户的使用偏好,就能够更好的为用户提供服务
request.session ---> 保存在服务端的一个类似于字典的对象
浏览器同时还是用了本地存储技术 ---> cookie ---> 用户身份信息(sessionid)
---> HTTP请求头会携带本网站的cookie信息 ---> sessionid --->
和用户关联的那个session对象 ---> 获取之前保存在session中的数据 ---> 用户跟踪浏览器实现本地存储有多种方案:
~ cookie(使用起来最简单,浏览器兼容性最好)
~ localStorage / sessionStorage
~ IndexDBrequest.session['...'] = ...
python manage.py clearsessions
-
Django项目接入Redis实现缓存服务
memcached ---> Redis ---> Django接入Redis
pip install django-redisCACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://主机:端口/0',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
'PASSWORD': 'Redis口令'
}
}
}SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_CACHE_ALIAS = 'default' -
导出Excel文件
Office 2010 ---> Excel 2010 ---> openpyxl
Office 2003 ---> Excel 2003 ---> xlwt / xlrdWorkbook ---> sheet ---> sheet['A1'] ---> save()
BytesIO --- getvalue() ---> bytes ---> HttpResponse
~ content-type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
~ content-disposition: inline / attachment; filename=... 生成统计图表
前端接入ECharts ---> 通过JavaScript实现图表效果渲染
后端提供JSON数据 ---> JsonResponse原生SQL查询
django.db.transaction.get_connection() ---> Connection对象
---> cursor() ---> execute() ---> fetchone() / fetchmany() / fetchall()-
中间件(拦截过滤器)
def simple_middleware(get_response):def middleware(request, *args, **kwargs): response = get_response(request) return response return middleware
Django中间件与之前学过的装饰器在写法和用途上都非常接近,
通过Django项目配置文件的MIDDLEWARE可以配置使用中间件 调用三方服务(你自己无法完成的功能)
~ SDK集成 --->
- pip install alipay-python-sdk
- pip install qiniu
~ API调用 ---> URL统一资源定位符 ---> HTTP ---> JSON
- pip install requests
request.get(url) / requests.post(url, data={...})ORM框架调优
~ 限制查询字段:only / defer
~ 解决1+N查询:select_related / prefetch_related
~ Q对象 / F对象-
Django-Debug-Toolbar
INSTALLED_APPS ---> 'debug_toolbar'MIDDLEWARE ---> 'debug_toolbar.middleware.DebugToolbarMiddleware'
DEBUG_TOOLBAR_CONFIG = {
# 引入jQuery库
'JQUERY_URL': 'https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js',
# 工具栏是否折叠
'SHOW_COLLAPSED': True,
# 是否显示工具栏
'SHOW_TOOLBAR_CALLBACK': lambda x: True,
}if settings.DEBUG:
import debug_toolbar
urlpatterns.insert(0, path('debug/', include(debug_toolbar.urls)))
-
日志配置
~ 级别:DEBUG < INFO < WARNING < ERROR < CRITICALLOGGING = {
'version': 1,
'disable_existing_loggers': False,
# 配置日志格式化器
'formatters': {
'simple': {
'format': '%(asctime)s %(module)s.%(funcName)s: %(message)s',
'datefmt': '%Y-%m-%d %H:%M:%S',
},
'verbose': {
'format': '%(asctime)s %(levelname)s [%(process)d-%(threadName)s] '
'%(module)s.%(funcName)s line %(lineno)d: %(message)s',
'datefmt': '%Y-%m-%d %H:%M:%S',
}
},
# 配置日志过滤器
'filters': {
'require_debug_true': {
'()': 'django.utils.log.RequireDebugTrue',
},
},
# 配置日志处理器
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'level': 'DEBUG',
'filters': ['require_debug_true'],
'formatter': 'simple',
},
'file1': {
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': 'access.log',
'when': 'W0',
'backupCount': 12,
'formatter': 'simple',
'level': 'INFO',
},
'file2': {
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': 'error.log',
'when': 'D',
'backupCount': 31,
'formatter': 'verbose',
'level': 'WARNING',
},
},
# 配置日志器
'loggers': {
'django': {
'handlers': ['console', 'file1', 'file2'],
'propagate': True,
'level': 'DEBUG',
},
}
} -
其他知识点
~ DTL:Django模板语法
模板指令:
- {% if %} / {% else %} / {% endif %}
- {% for %} / {% endfor %}
过滤器:
- lower / upper / first / last / truncatewords / date/ time
/ length / pluralize / center / ljust / rjust / cut / urlencode
/ default_if_none / filesizeformat / join / slice / slugify~ 路径参数
- Django 1.x:url(r'mcode/(?P<mobile>1[3-9]\d{9})')
- Django 2.x:path('mcode/<str:mobile>')~ base64编码:用64个可读文本符号表示任意二进制数据
base64.b64encode / base64.b64decode