Django简介
前面已经详细介绍过flask框架了(
https://blog.csdn.net/nie7342/article/details/101122347
https://blog.csdn.net/nie7342/article/details/101292571),相对flask,Django是一个重量级框架,它强调代码复用,多个组件可以很方便的以"插件"形式服务于整个框架,Django有许多功能强大的第三方插件,我们甚至可以很方便的开发出自己的工具包。
MVC:
M: model层,负责 数据处理,包括对数据的增删改查等操作
V: view层,负责 界面显示
C: controller层,负责逻辑控制接收和处理请求,调用model和view
核心思想: 分层,解耦。MVC分离了 数据处理 和 界面显示 的代码,使得一方代码修改了不会影响到另外一方,提高程序的扩展性和可维护性。
Django是基于MVT的一种设计模式:
M: Model, 模型 与MVC中的M相同,负责对数据的处理
V: View, 视图 与MVC中的C类似,负责处理用户请求,调用M和T,响应请求
T: Template, 模板 与MVC中的V类似,负责如何显示数据(产生html界面)
Django项目搭建
一般我们建议在一个IDE中如果有不同的模块,如flask,爬虫,Django等,我们可以建虚拟环境,以避免各API或者安装环境的差异
1.新建虚拟环境
mkvirtualenv django_py3 -p python3
2.安装Django
pip install django==1.11.11
3.创建项目 django-admin startproject Django02
4.创建运用 python manage.py startapp users
从浏览器发起请求到做出响应的步骤:
浏览器发出http请求–>Django封装request–>url匹配对应视图函数–>Djanso返回并解析response对象–>浏览器渲染并展示内容
Django配置文件
在项目的 setting.py 配置文件中,进行项目相关配置的修改。
当前项目的根目录,Django会依此来定位工程内的相关文件,我们也可以使
用该参数来构造文件路径
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
开启debug = True,项目运行出错了,需要查看是哪里一行代码造成出错,再进行分析解决
修改本地语言与时区
LANGUAGE_CODE = 'zh-hans' # 语言设置为 中文
TIME_ZONE = 'Asia/Shanghai' # 时区设置为 亚洲/上海,注意没有北京
App应用配置:每次我们创建一个app的时候都需要在项目配置文件 settings.py 中的 INSTALLED_APPS 列表中进行绑定,这样才能运行。
静态文件配置:
1.在项目根目录下创建 static_files 目录,并添加子目录和文件 imgs/avatar01.png
2.在 项目 settings.py 文件中进行配置
# 告知Django静态文件保存在哪个目录下
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static_files')]
URL配置:为了减轻项目的URL配置,我们可以在每个app底下建一个自己的url然后在总项目的URL中去include每个app的URL文件
例如:
项目下的 urls.py 文件
urlpatterns = [
# 包含users模块下的urls.py
# 参数1: 匹配url的正则表达式
# 参数2: 调用 inclucde 函数,包含users模块下的urls.py
url(r'^users/', include('users.urls')),
]
#APP底下的 urls.py 文件 (此文件默认不存在,需要自己创建)
urlpatterns = [
# 配置url和视图函数,需要调用url函数,并传入参数
# 参数1: 匹配url的正则表达式(需要用 ^ 和 $ 匹配开头和结尾)
# 参数2: url匹配成功执行的视图函数
url(r'^index$', views.index),
]
请求与响应
客户端的传参方式:
1通过URL路径传递:例如http://127.0.0.1:8000/news/1/2 传递id和页码
2.通过查询字符串传递:http://127.0.0.1:8000/news?category=1&page=2
3.通过body传递:body传递的数据又可分为键值对,表单和非标单数据
键值对:category=1&page=2,非标单数据:如json或者xml {“category”: 1, “page”: 2}
4.通过http协议请求头传递
通过request获取请求参数
1.获取查询字符串: request.GET.get('参数名 '),如果是一键多值:request.GET.getlist(‘参数名’)
请求地址:http://127.0.0.1:8000/news2?category=1&page=2
def index(request):
category = request.GET.get('category ')
page = request.GET.get('page')
# ?category=1&page=2&a=3&a=4
# a = request.GET.getlist('a') # 一键多值通过 getlist 获取
text = '<br/> category=%s, page=%s' % (category, page)
return HttpResponse(text)
2.获取请求体数据:请求体数据格式不固定,可以是json或者xml类型,应区别对待。可以发送请求体数据的请求方式有POST、PUT、PATCH、DELETE
获取表单数据 Form Data (键值对):request.POST.get(‘参数名’)
request.POST.get只能获取post方式提交的表单数据,如果是非post或者非表单类型的数据需要用request.body属性获取提交的数据后,再自己手动解析
def news3(request):
category = request.POST.get('category')
page = request.POST.get('page')
# 一键多值通过从POST中用 getlist 获取
# ?category=1&page=2&a=3&a=4
# a = request.POST.getlist('a')
text = '获取body中的键值对:<br/> category=%s, page=%s' % (category, page)
return HttpResponse(text)
非表单类型 Non-Form Data:如获取json, request.body–> json.loads转换成dict类型,然后按键取值
def news4(request):
# 获取json字符串
json_str = request.body
# 解析json
dict_data = json.loads(json_str)
category = dict_data.get('category')
page = dict_data.get('page')
text = '获取body中的json数据: category=%s, page=%s' % (category, page)
return HttpResponse(text)
Response
视图必须返回一个HTTPResponse对象或者HTTPResponse的子类对象而不能直接返回字符串,HTTPResponse常用的子类有:HttpResponseRedirect (重定向),JsonResponse (json)
- HttpResponse
HTTPResponse(content = ‘内容’,content_type=响应体数据MIME类型, status=状态码)
MIME类型包含以下三种:
text/html html
text/plain 普通文本
application/json json
2.JsonResponse:返回json数据,同时设置响应头 Content-Type 为 application/json
def resp(request):
return JsonResponse({'city': 'beijing', 'subject': 'python'})
但是当我们返回的data中包含中文的时候不可以直接返回,需要加上编码
def resp(request):
# 最终看到的效果是: {"name": "\u5f20\u4e09"}
response = JsonResponse({"name":"张三"})
response = JsonResponse(data, json_dumps_params={'ensure_ascii':False})
return response
3.redirect重定向
def resp(request):
# 重定向到首页
return redirect('/index')
4.reverse函数:根据映射名称找到正确的URL地址
url = reverse(‘users:index’)
cookie和session
cookie是由服务器生成的保存在客户端的数据,HTTP请求本来是无状态的,cookie可以追踪用户的访问记录,在响应请求时服务器会将cookie发送给浏览器,浏览器在请求服务器的时候会带上服务器返回的所有未过期的cookie
1.在服务端设置cookie
response.set_cookie(‘键’, ‘值’,max_age)
2.在客户端读取cookie
request.COOKIES[‘键’]
session也是服务器端生成的只不过session保存于服务器而非本地,且session多保存敏感信息,session依赖于cookie
1.设置session: request.session[‘键’]=值
2.读取session:request.session.get(‘键’, 默认值)
3.删除session: del request.session[‘键’]#当键不存在的时候会报错
request.session.flush() # 删除一条表记录
request.session.clear() # 清空字段中的session键值对数据
4.设置过期时间:request.session.set_expiry(value)#如果不设置默认为两周
5.配置将session保存到Redis当中
pip install django-redis==4.8.0
然后修改settings,新增如下配置:
# django项目的缓存配置
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"PASSWORD": ""
}
}
}
# session数据缓存到Redis中
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"
类视图
上代码:
from django.views.generic import View
class PostView(View):
def get(self, request):
"""get请求: 显示发帖界面"""
return render(request, 'post2.html')
def post(self, request):
"""post请求: 执行发帖操作"""
# 代码简略
return HttpResponse('执行发帖操作')
urlpatterns = [
...
# 类视图注册
url(r'^post2$', views.PostView.as_view()),
]
如果我们想用一个视图实现get,post两个请求,推荐使用类视图,虽然函数视图也可以实现但需要我们手动判断请求方式。然后普通视图函数的URL直接是views.视图函数名,但类视图函数得用as_view来转换。对于函数视图代码可读性和复用性更好。
类视图装饰器:
1.直接在URL中进行装饰
urlpatterns = [
...
# 发帖功能
url(r'^post2$', check_ip(views.PostView.as_view())) #check_ip为我们装饰器的名字
]
2.在类方法中进行装饰:利用method_decorator(装饰器名)
@method_decorator(check_ip)
def get(self, request):
"""get请求:显示发帖界面"""
return render(request, 'post2.html')
3.类视图多继承 & Mixin扩展类
学过c++的其实很容易理解,比如我们新建class A拥有遍历方法,新建class B拥有增加方法,然后我们有class C同时继承了A和B类,然后C类有自己的删除方法,于是C类就有了遍历,新建和删除这三个方法。类视图的多继承便于代码的复用和扩展。
class ListModelMixin(object):
"""
list扩展类
"""
def list(self, request, *args, **kwargs):
print('查询多条数据')
...
class CreateModelMixin(object):
"""
create扩展类
"""
def create(self, request, *args, **kwargs):
print('新增一条数据')
...
class DepartmentView(CreateModelMixin, ListModelMixin, View):
"""
同时继承两个扩展类,复用list和create方法
"""
def get(self, request):
self.list(request)
...
def post(self, request):
self.create(request)
...
class EmployeeView(CreateModelMixin, View):
"""
继承CreateModelMixin扩展类,复用create方法
"""
def post(self, request):
self.create(request)
...
中间件
什么叫中间件?中间件的作用和装饰器很类似,用于在视图函数调用之前或之后执行额外操作,在全局上修改Django的输入或输出,而装饰器只能对被装饰的单个函数起作用。
1.定义中间件类: 通过继承Django的MiddlewareMixin扩展类实现:
init(self, get_response=None)服务器启动,初始化中间件类时被调用,只执行一次 process_request(self, request):在视图执行之前调用,注意:该方法可以返回None或者response对象,如果返回response对象,则视图函数就不会再执行了
process_response(self, request, response): 在视图执行之后调用,必须返回 response 对象
2.在setting.py文件中的MIDDLEWARE中注册
新建一个middleware.py然后写一个简单的中间件
class MyMiddleware(MiddlewareMixin):
def __init__(self, get_response=None):
super().__init__(get_response)
print('init')
def process_request(self, request):
print('before 视图')
# 注意:可以返回None或者response对象,如果返回response对象,则视图函数就不会再执行了
def process_response(self, request, response):
print('after 视图')
return response
代码写完之后在settings中注册我们的中间件,这样才能被启用
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
...
'middlewares.MyMiddleware', # 注册中间件
]
这样就OK了,我们随便运行哪个视图函数都会起到我们的中间件。
那么如果我们定义了多个中间件的话执行顺序是这样的:
对于视图之前执行的 process_request 方法,先 注册的中间件先执行
对于视图之后执行的 process_response 方法,后 注册的中间件先执行
模板
模板这里主要补充一下Django渲染模板的方法,Django依旧使用模板语言Jinjia2,参考前面的flask教程(https://blog.csdn.net/nie7342/article/details/101292571)
1.配置模板文件
在项目根目录下创建模板目录,比如叫 templates,后续开发模板文件会放在此目录下
2.在项目的配置文件settings.py文件中,进行模板目录的配置,如下:
2.模板渲染
Django支持两张类型的模板渲染
#利用render直接渲染render(请求对象,模块路径,字典数据)
def index(request):
context = {'name': 'django' }
# 参数1:请求对象
# 参数2:模块路径
# 参数3:字典数据
return render(request, 'index.html', context)
#利用template.render()进行渲染,在渲染之前我们需要通过 loader.get_template来获取template对象
def index(request):
# 获取模板对象
template = loader.get_template('index.html')
# 渲染得到字符串
html_str = template.render(context)
# 响应请求
return HttpResponse(html_str)
还有关于Django数据库以及admin站点的总结会抽时间奉上。