MTV模式
model-template-view(模型-模板-视图)模式,模板是一个文本,用于分离文档的表现形式和内容。MTV 模式本质上与 MVC (Mode-View-Controller)相同,都是让各组件保持低耦合的关系。
MVC模式中:
- M:模型(Model),数据存取层,负责业务对象和数据库对象。
- V:视图(View),与用户的交互,负责显示与怎样显示。
- C:控制器(Controller),接受用户动作,调用模型,输出相应视图。三者像插件一样以松耦合的形式连接在一起。
MTV 具体定义如下:
M:模型(Model),负责业务对象和数据库的关系映射。
T:模板(Template),负责如何把页面展示给用户。
V:视图(View),负责业务逻辑,并在适当时候调用模型和模板。
URL分发器
URL 分发器的作用是将页面请求分发给不同的视图(View)处理,视图再调用相应的模型(Model)和模板(Template)。
初始设置
修改配置文件
在settings.py
文件中修改配置,
- 修改允许访问的 IP 地址
ALLOWED_HOSTS=['*'] #增加一个匹配任意主机地址的字符串
- 修改数据库配置项
用mysql数据库替代默认的sqlite数据库。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # 引擎由 Django 提供
'NAME': 'myproject', # 数据库的名字
'USER': 'root', # 用户默认为 root
'PASSWORD': '', # 没有设置密码
'HOST': '127.0.0.1', # 本地连接,固定 IP
'PORT': 3306 # 固定端口号
}
}
- 模板文件路径设置
浏览器发送请求给服务器,服务器派遣对应的视图类处理请求,需要模板文件提供支持返回响应,模板相关的设置在TEMPLATES
列表下,该列表中默认有一个字典对象,其中DIRS
字段的值是列表,该值对应模板文件的相对路径。
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': ['myproject/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',
],
},
},
]
- 静态文件路径设置
模板文件需要调用静态资源进行渲染,静态资源的配置项为STATICFILES_DIRS
,
它是一个列表,里面要写入静态资源的路径。该配置项不会自动生成,需要新建:
STATICFILES_DIRS = ['myproject/static']
创建应用
进入myproject
文件夹下输入命令:
$ python3 manage.py startapp [appname]
再次编辑 myproject/settings.py
文件,修改INSTALLED_APPS
元组,该配置项用于注册应用,将 ‘appname’ 字符串写入其中:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'share',
]
初始化数据库
先设置mysql数据库:…未完待续
针对每个 Django 项目,都有一些项目必需的数据表,执行如下命令创建它们的迁移文件并在 myproject 数据库中创建它们:
$ python3 manage.py makemigrations
$ python3 manage.py migrate
启动项目
在启动项目前先检查项目是否有疏漏,no issues则说明项目可以正常启动:
$ python3 manage.py check
启动项目使用runserver
选项,后面的参数为主机地址:端口号
,我们使用 0:8080 表示任意 IP 地址的 8080 端口启动程序:
$ python3 manage.py runserver 0:8080
文件上传和分享功能
实现视图功能
Django 提供了很多视图基类,以便于根据它们快速编写所需要的视图类。我们写的视图类只需要继承这些基类,便可以实现很强大的功能。
编辑 appname/views.py
文件 ,将以下代码写入其中:
from django.shortcuts import render
from django.views.generic import TemplateView,ListView
# 创建视图类需要基础视图基类
# 例如 TemplateView 就是用于展示页面的模板视图基类
# 该类仅提供 get 方法,用于处理 GET 请求
# 当然也可以自定义其它方法,例如 post
class HomeView(TemplateView):
'''用来展示主页的视图类
'''
# 展示主页的话,只需要提供模板文件的名字即可
# 当客户端发起 get 请求时,由父类的 get 方法处理请求
# 该属性用于提供模板文件,在父类的方法中被调用
template_name = 'base.html'
创建映射类(创建数据库表格)
Django 自己提供了一套 ORM 机制,使开发者不用关心 SQL 语句。定义一个普通的模型类(也叫“映射类”),需要继承 models.Model 类,后者是模型类的基类。模型类中的常用字段类:
CharField (字符串)
IntegerField (整数)
DateTimeField (常用的时间字段)
TextField (大容量文本字段)
字段属性:
default = 0 设置默认值
max_length = 23 设置字段长度最大值
min_length = 5 设置字段长度最小值
verbose_name = “” 指明了字段一个易于理解的名字
创建上传文件所需的映射类 Upload ,将以下代码写入 appname/models.py 文件:
from django.db import models
from datetime import datetime
class Upload(models.Model):
'''上传文件使用的映射类
'''
# 访问页面的次数
downloadcount = models.IntegerField(verbose_name='访问次数', default=0)
# 该字段作为一个文件的唯一标识
code = models.CharField(verbose_name='code', max_length=8)
# 文件上传时间
datetime = models.DateTimeField(verbose_name='上传时间',
default=datetime.now())
# 文件存储路径
path = models.CharField(verbose_name='存储路径', max_length=64)
# 文件名
name = models.CharField(verbose_name='文件名', max_length=32)
# 文件大小
filesize = models.CharField(verbose_name='文件大小', max_length=8)
# 上传文件的客户端的 IP 地址
pcip = models.CharField(verbose_name='IP 地址', max_length=16)
# 这个方法用于格式化类的实例的打印样式,便于测试
def __str__(self):
return self.name
定义好模型类,就可以进行数据迁移了。数据库已经准备好,执行如下命令创建迁移文件:
$ python3 manage.py makemigrations
进行文件迁移(实质是创建数据表):
$ python3 manage.py migrate
配置首页路由
路由管理由 myproject/urls.py 文件中的urlpatterns
列表负责。在列表中添加一项关于主页的路由规则,其实就是一个 path 方法的调用。文件修改如下:
from django.contrib import admin
from django.urls import path
from appname.views import HomeView
urlpatterns = [
path('admin/', admin.site.urls),
# 当用户发起主页的 GET 请求时
# 会调用 HomeView 的父类的 get 方法处理
# 怎么调用呢,这需要用到 HomeView 的父类的 as_view 方法
# 此方法会调用 dispatch 方法,由后者根据请求类型选择相应的处理函数
path('', HomeView.as_view(), name='home'),
]
其中的 path 方法的第一个参数为相对路径,空字符串表示根目录,即主页路由;name 参数可以用在前端模板文件中。
启动项目
$ python3 manage.py runserver 0:8080
文件上传功能
添加处理首页POST请求的方法
修改 share/views.py 文件中的 HomeView 视图类。该视图类继承了 TemplateView 类,后者并未提供处理 POST 请求的方法,所以需要自定义一个 post 方法。
import random
import string
import datetime
import json
from django.shortcuts import render
from django.views.generic import TemplateView, ListView
from django.http import HttpResponse, HttpResponsePermanentRedirect
from .models import Upload
class HomeView(TemplateView):
'''用来展示主页的视图类
'''
template_name = 'base.html'
def post(self, request):
# 如果表单中有文件
if request.FILES:
file = request.FILES.get('file')
name = file.name
size = int(file.size)
path = 'myproject/static/file/' + name
with open(path, 'wb') as f:
f.write(file.read())
code = ''.join(random.sample(string.digits, 8))
upload = Upload(
path = path,
name = name,
filesize = size,
code = code,
pcip = str(request.META['REMOTE_ADDR'])
)
upload.save()
return HttpResponsePermanentRedirect("/s/"+code)
创建展示文件信息的视图类
上传文件的 POST 请求就使用 HomeView 中定义的 post 方法来处理,最后的返回值是重定向类的实例,这需要浏览器自动跳转到另一个页面。所以需要再定义一个视图类,用于处理展示文件信息。
在 appname/views.py 文件中定义 DisplayView 类用于展示文件信息:
class DisplayView(ListView):
'''展示文件的视图类
'''
def get(self, request, code):
uploads = Upload.objects.filter(code=code)
if uploads:
for upload in uploads:
upload.downloadcount += 1
upload.save()
return render(request, 'content.html', {'content': uploads, 'host': request.get_host()})
增加路由并启动项目
在 myproject/urls.py 文件中添加文件展示的路由:
from django.contrib import admin
from django.urls import path
from appname.views import HomeView, DisplayView
urlpatterns = [
path('admin/', admin.site.urls),
path('', HomeView.as_view(), name='home'),
path('s/<code>', DisplayView.as_view(), name='display'),
]
这样已经完成文件上传功能,启动项目:
$ python3 manage.py runserver 0:8080
实现用户管理功能和搜索功能
首先在appname/views.py 中添加一个视图类 MyView 用来处理用户管理页面,新增代码如下:
class MyView(ListView):
'''用户管理视图类,就是用户管理文件的那个页面的视图类
'''
def get(self, request):
ip = request.META['REMOTE_ADDR']
uploads = Upload.objects.filter(pcip=ip)
for upload in uploads:
upload.downloadcount += 1
upload.save()
return render(request, 'content.html', {'content': uploads})
常用的 ORM 查询操作:
ModelName.object.all() # 返回 model 的所有数据集
ModelName.object.filter(**kwargs) # 返回符合筛选条件的数据集
ModelName.object.exclude(**kwargs) # 返回不符合筛选条件的数据集
ModelName.object.get(**kwargs) # 用于查询单条记录
为用户管理增加路由,修改 myproject/urls.py 文件如下:
from django.contrib import admin
from django.urls import path
from share.views import HomeView, DisplayView, MyView
urlpatterns = [
path('admin/', admin.site.urls),
path('', HomeView.as_view(), name='home'),
path('s/<code>', DisplayView.as_view(), name='display'),
path('my/', MyView.as_view(), name='my'),
]
用户搜索功能
在 appname/views.py 中新建一个 SearchView 视图类提供搜索功能:
class SearchView(ListView):
'''搜索功能的视图类
'''
def get(self, request):
code = request.GET.get('kw')
u = Upload.objects.filter(name__icontains=str(code))
data = {}
if u :
# 将符合条件的数据放到 data 中
for i in range(len(u)):
u[i].downloadcount += 1
u[i].save()
data[i]={}
data[i]['download'] = u[i].downloadcount
data[i]['filename'] = u[i].name
data[i]['id'] = u[i].id
data[i]['ip'] = str(u[i].pcip)
data[i]['size'] = u[i].filesize
data[i]['time'] = str(u[i].datetime.strftime('%Y-%m-%d %H:%M'))
# 时间格式化
data[i]['key'] = u[i].code
# django 使用 HttpResponse 返回 json 的标准方式,content_type 是标准写法
return HttpResponse(json.dumps(data), content_type="application/json")
搜索功能主要是利用关键字搜索数据表 share_upload 中的 name 字段的值,使用映射类的 Upload.objects.filter 方法实现搜索,参数为 name_icontains ,表示搜索 name 属性中包含某个字段的实例,不区分大小写。
修改一下 myproject/urls.py 文件,增加搜索功能的路由:
from django.contrib import admin
from django.urls import path
from appname.views import HomeView, DisplayView, MyView, SearchView
urlpatterns = [
path('admin/', admin.site.urls),
path('', HomeView.as_view(), name='home'),
path('s/<code>', DisplayView.as_view(), name='display'),
path('my/', MyView.as_view(), name='my'),
path('search/', SearchView.as_view(), name='search'),
]
参考文章
streamlit
django生态
Django-rest-framework
Django-debug-toolbar
Django-extensions
Sentry-sdk
Django-allauth
Django-filter