学习日记之《Django3 Web应用开发实战》
- 第二章——Django 配置信息
- 第三章——初探路由
- 第四章——探究FBV视图
- 第五章——CBV视图
- 第六章——深入模板
- 第七章——模型与数据库
- 第八章——表单和模型
- 第九章——Admin 后台系统
- 第十章——Auth 认证系统
- 第十一章——常用的web应用程序
第二章——Django 配置信息
1、静态资源和媒体资源
# settings.py
# Django只能识别项目应用APP的static文件夹的静态资源,这是由INSTALLED_APPS->django.contrib.staticfiles实现的
STATIC_URL = '/static/' # 静态资源路由
# 资源集合,列表中可设置多个访问静态资源的地址
STATICFILES_DIRS = [ BASE_DIR / 'StaticFiles']
# STATIC_ROOT主要收集整个项目的静态资源并存放在一个新的文件夹,然后由该文件夹与服务器之间构建映射关系
# 当项目的配置属性DEBUG设为True的时候,Django会自动提供静态文件代理服务(STATIC_URL),此时整个项目处于开发阶段,因此无须使用STATIC_ROOT。当配置属性DEBUG设为False的时候,意味着项目进入生产环境,Django不再提供静态文件代理服务,此时需要在项目的配置文件中设置STATIC_ROOT。
# 设置STATIC_ROOT需要使用Django操作指令collectstatic来收集所有静态资源,这些静态资源都会保存在STATIC_ROOT所设置的文件夹里。
STATIC_ROOT = BASE_DIR / 'Allstatic' # 资源部署
# 媒体资源:存放媒体信息,如音视频,文件等
MEDIA_URL = "/media/" # 媒体路由地址
MEDIA_ROOT = BASE_DIR / "media" # 媒体路径信息
# 项目urls.py 设置
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.conf.urls.static import static
from django.conf import settings
from django.views.static import serve
方式一
urlpatterns += staticfiles_urlpatterns()
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
or
方式二
urlpatterns += [re_path("media/(?P<path>.*)", serve, {
"document_root": settings.MEDIA_ROOT}, name='media')]
2、模板配置
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR, 'templates'], # 可自定义模板的位置 名称 templates 固定
'APP_DIRS': True, # 默认可以识别每个应用下的 templates
'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',
],
},
},
]
3、数据库配置
连接mysql举例:
安装
pip3 install pymysql
在项目(和settings.py同目录)下的__init__.py设置
import pymysql
pymysql.install_as_MySQLdb() # 设置数据库连接模块即可
MySQL配置方式
方式一:直接配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_db', # 提前在MySQL中创建该名称的数据库
'USER':'root', # MySQL登录的用户名
'PASSWORD': '123', # MySQL登录的密码
'HOST':'127.0.0.1',
'PORT':'3306',
}
}
方式二:动态配置数据库连接
先创建一个连接数据库的配置信息,比如my.cnf
填写如下内容:
[client]
database=django_db
user=root
password=123
host=127.0.0.1
port=3306
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'OPTIONS':{
'read_default_file':str(BASE_DIR / 'my.cnf')},
}
}
多数据库连接配置
多数据库下,如果没有指定具体存储到那个数据库,默认存储到default名的数据库下。
DATABASES = {
# 第一个数据库
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_db0',
'USER':'root',
'PASSWORD': '123',
'HOST':'127.0.0.1',
'PORT':'3306',
},
# 第二个数据库
'mydjango': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_db1',
'USER':'root',
'PASSWORD': '123',
'HOST':'127.0.0.1',
'PORT':'3306',
}
}
通过SSH隧道远程连接数据库
pip3 install sshtunnel
# 设置settings.py
# 数据库服务器的IP地址或主机名
ssh_host = 'XXX.XXX.XXX.XXX'
# 数据库服务器的SSH连接端口号,一般是22,必须是数字
ssh_port = 22
# 数据库服务器的用户名
ssh_user = 'root'
# 数据库服务器的密码
ssh_password = '123'
# 数据库服务器的mysql的主机名或IP
mysql_host = 'localhost'
# 数据库服务器的mysql的端口,默认是3306
mysql_port = 3306
# mysql的用户名
mysql_user = 'root'
# mysql的密码
mysql_password = '123'
# mysql的数据库名
mysql_db = 'mydjango'
from sshtunnel import open_tunnel
def get_ssh():
server = open_tunnel(
(ssh_host, ssh_port),
ssh_username=ssh_user,
ssh_password=ssh_password,
# 绑定服务器的mysql数据库
remote_bind_address=(mysql_host, mysql_port)
)
server.start()
return str(server.local_bind_port)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': mysql_db,
'USER':mysql_user,
'PASSWORD': mysql_password,
'HOST':mysql_host,
'PORT':get_ssh(),
}
}
4、中间件介绍
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', # 内置安全机制,保护用户和网络的通信安全
'django.contrib.sessions.middleware.SessionMiddleware', # 会话Session功能
'django.middleware.locale.LocaleMiddleware', # 国际化和本地化中间件
'django.middleware.common.CommonMiddleware', # 处理请求信息,规范化请求内容
'django.middleware.csrf.CsrfViewMiddleware', # 开启CSRF防护功能
'django.contrib.auth.middleware.AuthenticationMiddleware', # 开启内置的用户认证系统
'django.contrib.messages.middleware.MessageMiddleware', # 开启内置的信息提示功能
'django.middleware.clickjacking.XFrameOptionsMiddleware', # 防止恶意程序单机劫持
]
第三章——初探路由
1、反向解析
from django.shortcuts import reverse # 生成路由地址
from django.urls import resolve # 通过路由地址生成路由对象
reverse('index:mydate', args=args)
reverse('index:mydate', kargs=kargs)
result= resolve(reverse('index:mydate', args=args)) # 了解一下生成的对象有哪些方法和属性
2、重定向
from django.shortcuts import redirect # 指定跳转到指定的路由地址
redirect(reverse('index:mydate', args=args)) # 一种方式是使用路由
redirect('index:mydate', permanent=True) # 一种方式是使用路由命名,可以指定是否永久重定向
第四章——探究FBV视图
1、异常响应
Django配置全局异常响应
注意:必须在项目名的urls.py下配置
项目下的urls.py
# 全局404页面配置
handler404 = 'index.views.page_not_found' # 连接到指定的路由处理
# 全局500页面配置
handler500 = 'index.views.page_error' # 连接到指定的路由处理
验证是否生效:需要在settings.py 设置DEBUG=False 和 ALLOWED_HOSTS=['*']
2、文件下载功能
# views.py
import os
from django.shortcuts import render
from django.http import HttpResponse, Http404
from django.http import StreamingHttpResponse
from django.http import FileResponse
# Create your views here.
def index(request):
return render(request, 'index.html')
file_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
file_path1 = file_path + '/media/cat1.png'
file_path2 = file_path + '/media/cat2.png'
file_path3 = file_path + '/media/cat3.png'
def download1(request):
try:
r = HttpResponse(open(file_path1, 'rb'))
r['content_type'] = 'application/octet-stream'
r['Content-Disposition'] = 'attachment;filename=cat1.png'
return r
except Exception:
raise Http404("Download error")
def download2(request):
try:
r = StreamingHttpResponse(open(file_path2, 'rb'))
r['content_type'] = 'application/octet-stream'
r['Content-Disposition'] = 'attachment;filename=cat2.png'
return r
except Exception:
raise Http404("Download error")
def download3(request):
try:
f = open(file_path3, 'rb')
r = FileResponse(f, as_attachment=True, filename='cat3.png')
return r
except Exception:
raise Http404("Download error")
说明:
HttpResponse:不建议使用,消耗内存
StreamingHttpResponse:建议使用,支持大规模数据或者文件输入,需提供数据格式和文件格式
FileResponse:仅支持文件输入
3、文件上传功能
无论上传的文件是什么格式,其上传原理都是将文件以二进制的数据格式读取并写入网站指定的文件夹里
# views.py
def upload(request):
if request.method == "POST":
myFile = request.FILES.get("myfile", None)
if not myFile:
return HttpResponse("no file")
f = open(os.path.join(upload_path, myFile.name), 'wb+')
for chunk in myFile.chunks():
f.write(chunk)
f.close()
return HttpResponse("upload over")
else:
return render(request, "upload.html")
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Upload</title>
</head>
<body>
<form enctype="multipart/form-data" action="{%url 'test_app:upload'%}" method="post">
{
% csrf_token %}
<input type="file" name="myfile" />
<br>
<input type="submit" value="上传文件" />
</form>
</body>
</html>
关键点:enctype="multipart/form-data" 和 文件对象 type="file" name="myfile"
django 通过 request.FILES 获取该文件对象
for chunk in myFile.chunks():
f.write(chunk)
通过响应流的方式写入文件
自定义上传功能
# 自定义handler.py
from django.core.files.uploadhandler import *
from django.core.files.uploadedfile import *
class MyFileUploadHandler(TemporaryFileUploadHandler):
def new_file(self, *args, **kwargs):
super().new_file(*args, **kwargs)
print("this is my FileUploadHandle")
self.file = TemporaryUploadedFile(self.file_name,
self.content_type,
0,
self.charset,
self.content_type_extra)
# settings.py
# 配置文件数据临时存放的文件夹
FILE_UPLOAD_TEMP_DIR = upload_path
# 判断文件大小的条件
FILE_UPLOAD_MAX_MEMORY_SIZE = 209715200
# 配置文件上传的处理过程
FILE_UPLOAD_HANDLERS = ['web_test.handler.MyFileUploadHandler']
关于获取cookie
def create(request):
r = redirect(reverse('test_app:index'))
# r.set_cookie('uid', 'cookie_value')
r.set_signed_cookie('uuid', 'id', salt='my', max_age=60) # 设置 加密了
print('i am here')
return r
def mycookie(request):
cookie = request.COOKIES.get('uuid', '') # 获取
if cookie:
try:
m = request.get_signed_cookie('uuid', salt='my')
print('m', m)
except:
raise Http404('当前cookie无效')
return HttpResponse(f"cookie {
cookie}")
else:
return HttpResponse('hello world')
自定义加解密引擎
# mysigner.py
from django.core.signing import TimestampSigner
class MyTimestampSigner(TimestampSigner):
def sign(self, value):
print(value)
return value + 'Test'
def unsign(self, value, max_age=None):
print(value)
return value[0:-4]
# settings.py
# 默认的Cookie加解密引擎
# SIGNING_BACKEND = 'django.core.signing.TimestampSigner'
# 自定义cookie加解密引擎
SIGNING_BACKEND = 'web_test.mysigner.MyTimestampSigner'
第五章——CBV视图
数据显示视图
RedirectView 重定向视图
class TurnTO(RedirectView):
permanent = False
url = 'http://192.168.241.128:8080/download/file1' # 重定向的路地址
# pattern_name = 'test_app:index' # 重定向的路由地址,由路由命名 和url 二选一
query_string = True # 是否将当前路由的请求参数传到重定向的地址
def get_redirect_url(self, *args, **kwargs):
print('i am here')
return super().get_redirect_url(*args, **kwargs)
def get(self, request, *args, **kwargs):
print('hello world.')
return super().get(request, *args, **kwargs)
基础视图 TemplateView
from django.views.generic.base import TemplateView
class Index(TemplateView):
template_name = 'index1.html'
template_engine = None
content_type = None
extra_context = {
'title': 'this is get'}
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['value'] = 'Django'
return context
def post(self, request, *args, **kwargs):
self.extra_context = {
'title': 'this is post'}
context = self.get_context_data(**kwargs)
return self.render_to_response(context)
列表视图 ListView
from django.views.generic import ListView
from .models import PersonInfo
class PersonInfoView(ListView):
template_name = 'personinfo.html'
extra_context = {
'title': "人员信息表"}
queryset = PersonInfo.objects.all()
paginate_by = 1 # 每页展示的数据
context_object_name = 'personinfo' # 模板上下文
详细视图 DetailView
from django.views.generic import DetailView
class PersonInfoDetailView(DetailView):
template_name = 'info.html'
extra_context = {
'title': "人员信息表"}
slug_field = 'age' # 模型的查询字段
slug_url_kwarg = 'age' # 结合slug_field实现模型查询操作
pk_url_kwarg = 'pk'
model = PersonInfo
context_object_name = 'personinfo'
query_pk_and_slug = False
数据操作视图
from django.views.generic.edit import FormView
from .form import PersonInfoForm
def result(request):
return HttpResponse('success')
class ShowForm(FormView):
initial = {
'name': 'cooper', 'age': 20}
template_name = 'show.html'
success_url = '/result'
form_class = PersonInfoForm
extra_context = {
'title': '人员信息表'}
from django.views.generic.edit import CreateView
class CreateForm(CreateView):
initial = {
'name': 'cooper', 'age': 21}
template_name = 'show.html'
success_url = '/result'
model = PersonInfo
fields = ['name', 'age']
extra_context = {
"title": "人员信息表"}
from django.views.generic.edit import UpdateView
class UpdateForm(UpdateView):
template_name = 'show.html'
success_url = '/result'
model = PersonInfo
fields = ['name', 'age']
slug_url_kwarg = 'age'
slug_field = 'age'
context_object_name = 'personinfo'
extra_context = {
'title': '人员信息表'}
from django.views.generic.edit import DeleteView
class DeleteForm(DeleteView):
template_name = 'show.html'
success_url = '/result'
model = PersonInfo
context_object_name = 'personinfo'
extra_context = {
'title': '人员信息表'}
pk_url_kwarg = 'pk'
日期筛选视图
from .models import TimeInfo
from django.views.generic.dates import MonthArchiveView
class MonthView(MonthArchiveView):
allow_empty = True
allow_future = True
context_object_name = 'mylist'
template_name = 'time.html'
model = TimeInfo
date_field = 'hiredate'
queryset = TimeInfo.objects.all()
year_format = '%Y'
month_format = '%m'
paginate_by = 50
第六章——深入模板
自定义模板标签和自定义过滤器
# 项目目录下自定义文件夹如mytags,在mytags下创建templatestags(固定)文件夹,创建自定义标签功能
from django import template
# 创建模板对象
register = template.Library()
# 定义模板节点类
class ReversalNode(template.Node):
def __init__(self, value):
self.value = str(value)
def render(self, context):
return self.value[::-1]
# 声明并定义标签
# parse:解析器对象, token:被解析的对象
@register.tag(name='reversal')
def do_reversal(parse, token):
try:
tag_name, value = token.split_contents()
# tag_name: 标签名 value: 标签传递的数据
except:
raise template.TemplateSyntaxError('syntax')
# 调用自定义的模板节点类
return ReversalNode(value)
@register.filter(name='replace')
def do_replace(value, args):
oldvalue = args.split(':')[0]
newvalue = args.split(':')[1]
return value.replace(oldvalue, newvalue)
# 模板文件前load 自定义标签
<!DOCTYPE html>
{
% load custom_tags %}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{
% reversal 'Django' %} # 自定义标签
{
{
value | replace:'Python:Django' }} # 自定义过滤器
</body>
</html>
Jinja2模板引擎
pip3 install Jinja2
# 和settings.py 同目录创建jinja2_cus.py, 作用:将jinja2模板加载到django 项目中
from django.contrib.staticfiles.storage import staticfiles_storage
from django.urls import reverse
from jinja2 import Environment
# 将jinja2 模板设置到项目环境
def environment(**option):
env = Environment(**option)
env.globals.update({
'static': staticfiles_storage.url,
'url': reverse,
})
return env
settings.py
TEMPLATES = [
# 使用jinja2 模板引擎
{
'BACKEND': 'django.template.backends.jinja2.Jinja2',
'DIRS': [BASE_DIR, 'templates'],
'APP_DIRS'
标签:Web,name,视图,django,context,mysql,import,Django3,日记
From: https://blog.csdn.net/cooper_wx/article/details/136035763