名人说:莫道桑榆晚,为霞尚满天。------刘禹锡(刘梦得,诗豪)
创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊)目录
1、文件上传
1.在urls.py 中上传列表的路径
upload/list/
,并告诉该路径指向的视图upload_list
python
import chart as chart
from django.urls import path
from api.views import depart, user, pretty, admin, account, task, order, chart
urlpatterns = [
# 部门管理
path("depart/list/", depart.depart_list),
path("depart/add/", depart.depart_add),
path("depart/delete/", depart.depart_delete),
path("depart/<int:nid>/edit/", depart.depart_edit),
# 用户管理
path("user/list/", user.user_list),
path("user/add/", user.user_add),
path("user/model/form/add/", user.user_model_form_add),
path('user/<int:nid>/edit/', user.user_edit),
path("user/<int:nid>/delete/", user.user_delete),
# 靓号管理
path("pretty/list/", pretty.pretty_list),
path("pretty/add/", pretty.pretty_add),
path("pretty/<int:nid>/edit/", pretty.pretty_edit),
path("pretty/<int:nid>/delete/", pretty.pretty_delete),
# 管理员管理
path('admin/list/', admin.admin_list),
path('admin/add/', admin.admin_add),
path('admin/<int:nid>/edit/', admin.admin_edit),
path('admin/<int:nid>/delete/', admin.admin_delete),
path('admin/<int:nid>/reset/', admin.admin_reset),
# 用户登录
path('login/', account.login),
path('logout/', account.logout),
path('image/code/', account.image_code),
# 任务管理
path('task/list/', task.task_list),
path('task/ajax/', task.task_ajax),
path('task/add/', task.task_add),
# 订单管理
path('order/list/', order.order_list),
path('order/add/', order.order_add),
path('order/delete/', order.order_delete),
path('order/detail/', order.order_detail),
path('order/edit/', order.order_edit),
# 数据统计
path('chart/list/', chart.chart_list),
path('chart/bar/', chart.chart_bar),
path('chart/pie/', chart.chart_pie),
path('chart/line/', chart.chart_line),
# 文件上传
path('upload/list/', upload.upload_list),
]
2.在views文件夹下新建upload.py文件,以实现文件上传函数
python
import re
from django.shortcuts import render, HttpResponse
def upload_list(request):
# GET方法主要用于获取信息,而POST方法则用于提交数据
if request.method == "GET":
return render(request, "upload_list.html") # render函数负责将HTML模板渲染成最终的网页,并将这个网页返回给客户端。
# 声明图片的对象
file_object = request.FILES.get("avatar")
# 分块进行存储
# file_object.name 意思是图片上传前后保持原名称
f = open(file_object.name, mode='wb')
for chunk in file_object.chunks():
f.write(chunk)
f.close()
return HttpResponse("上传成功")
3.修改layout.html ,在templates目录下新建upload_list.html。

在layout.html中添加这一句,以便在网站里显示上传文件的列表选项:
html
<li><a href="/upload/list/">上传文件</a></li>
upload_list.html
html
{% extends 'layout.html' %}
{% block content %}
<div class="container">
<!--method为post,说明此处表单是提交数据-->
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="text" name="name">
<input type="file" name="avatar">
<input type="submit" value="提交">
</form>
</div>
{% endblock %}
上传文件

浏览器进行响应

此时就能发现,文件夹下多了一张咱们上传的图片。

基础的文件上传操作,咱们了解之后,之后来实现一下Excel表格上传。
2、Excel上传
目标:表格上传---》服务器读取保存---》数据库。
以部门管理为例,来进行操作。
1.编辑depart_list.html,增加文件上传板块。
depart_list.html
html
{% extends 'layout.html' %}
{% block content %}
<div class="container">
<div style="margin-bottom: 10px">
<a class="btn btn-success" href="/depart/add/">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
新建部门
</a>
</div>
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list" aria-hidden="true" style="margin-right: 5px;"></span>
<span>文件上传</span>
</div>
<div class="panel-body">
<form method="post" enctype="multipart/form-data" action="/depart/multi/">
{% csrf_token %}
<div class="form-group">
<input type="file" name="exc">
</div>
<input type="submit" class="btn btn-sm btn-info" value="上传">
</form>
</div>
</div>
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">
<span class="glyphicon glyphicon-list" aria-hidden="true"></span>
部门列表
</div>
<!-- Table -->
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>名称</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for obj in queryset %}
<tr>
<th>{{ obj.id }}</th>
<td>{{ obj.title }}</td>
<td>
<a class="btn btn-primary btn-xs" href="/depart/{{ obj.id }}/edit/">编辑</a>
<a class="btn btn-danger btn-xs" href="/depart/delete/?nid={{ obj.id }}">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<ul class="pagination">
{{ page_string }}
</ul>
</div>
{% endblock %}
2.安装
openpyxl
cmd
pip install openpyxl

补充:openpyxl是什么?
openpyxl
是一个Python库,用于读取和写入Excel 2010 xlsx/xlsm/xltx/xltm文件 。这个库允许你以编程方式操作Excel文件,比如创建新的工作簿、读取已有的工作簿、添加或删除工作表、修改单元格数据以及制作图表等。由于openpyxl
能够处理Excel文件,它在数据分析和自动化办公中尤其有用,为处理电子表格数据提供了很大的便利。
主要特性包括:
- 读取和写入Excel 2010 xlsx/xlsm文件。
- 修改工作簿和工作表,包括添加和删除工作表。
- 读取和修改单元格内容。
- 支持图表、图像和表格的创建和编辑。
- 样式和格式化,包括对文本和单元格的字体、边框、颜色等属性的设置。
通过openpyxl
,用户可以不依赖于Microsoft Excel应用程序,就能在Python脚本或应用中自动处理Excel文件。
3.在urls.py 中上传列表的路径
depart/multi/
,并告诉该路径指向的视图depart_multi
python
import chart as chart
from django.urls import path
from api.views import depart, user, pretty, admin, account, task, order, chart, upload
urlpatterns = [
# 部门管理
path("depart/list/", depart.depart_list),
path("depart/add/", depart.depart_add),
path("depart/delete/", depart.depart_delete),
path("depart/<int:nid>/edit/", depart.depart_edit),
# 用户管理
path("user/list/", user.user_list),
path("user/add/", user.user_add),
path("user/model/form/add/", user.user_model_form_add),
path('user/<int:nid>/edit/', user.user_edit),
path("user/<int:nid>/delete/", user.user_delete),
# 靓号管理
path("pretty/list/", pretty.pretty_list),
path("pretty/add/", pretty.pretty_add),
path("pretty/<int:nid>/edit/", pretty.pretty_edit),
path("pretty/<int:nid>/delete/", pretty.pretty_delete),
# 管理员管理
path('admin/list/', admin.admin_list),
path('admin/add/', admin.admin_add),
path('admin/<int:nid>/edit/', admin.admin_edit),
path('admin/<int:nid>/delete/', admin.admin_delete),
path('admin/<int:nid>/reset/', admin.admin_reset),
# 用户登录
path('login/', account.login),
path('logout/', account.logout),
path('image/code/', account.image_code),
# 任务管理
path('task/list/', task.task_list),
path('task/ajax/', task.task_ajax),
path('task/add/', task.task_add),
# 订单管理
path('order/list/', order.order_list),
path('order/add/', order.order_add),
path('order/delete/', order.order_delete),
path('order/detail/', order.order_detail),
path('order/edit/', order.order_edit),
# 数据统计
path('chart/list/', chart.chart_list),
path('chart/bar/', chart.chart_bar),
path('chart/pie/', chart.chart_pie),
path('chart/line/', chart.chart_line),
# 文件上传
path('upload/list/', upload.upload_list),
path('depart/multi/',depart.depart_multi),
]
4.修改depart.py ,增加depart_multi文件上传函数。
python
from django.shortcuts import render, redirect, HttpResponse
from api import models
from api.models import Department
from api.utils.pagination import Pagination
from openpyxl import load_workbook
def depart_list(request):
"""部门列表"""
queryset = models.Department.objects.all()
page_object = Pagination(request, queryset, page_size=2)
page_object.html()
context = {
"queryset": page_object.page_queryset,
"page_string": page_object.page_string,
}
return render(request, 'depart_list.html', context)
def depart_add(request):
"""添加部门"""
if request.method == "GET":
return render(request, 'depart_add.html')
# 获取用户POST提交过来的数据(title输入为空)
title = request.POST.get("title")
# 保存到数据库
models.Department.objects.create(title=title)
# 重定向回部门列表
return redirect("/depart/list/")
def depart_delete(request):
"""删除部门"""
# 获取ID
# http://127.0.0.1:8000/depart/delete/?nid=1
nid = request.GET.get('nid')
models.Department.objects.filter(id=nid).delete()
# 重定向回部门列表
return redirect("/depart/list")
def depart_edit(request, nid):
"""修改部门"""
if request.method == "GET":
# 根据nid,获取他的数据[obj,]
row_object = models.Department.objects.filter(id=nid).first()
return render(request, 'depart_edit.html', {"row_object": row_object})
# 获取用户的标题
title = request.POST.get("title")
# 根据ID找到数据库中的数据进行更新
models.Department.objects.filter(id=nid).update(title=title)
# 重定向回部门列表
return redirect("/depart/list/")
def depart_multi(request):
""" 文件上传(Excel) """
# 获取上传的 Excel 文件对象
file_object = request.FILES.get('exc')
print(file_object)
# 打开 Excel 文件读取内容
wb = load_workbook(file_object)
sheet = wb.worksheets[0]
# 循环获取每一行数据,并更新至数据库
for row in sheet.iter_rows(min_row=2):
exc_title = row[0].value
# 如果表格中的数据在数据库中不存在,则进行创建
if not Department.objects.filter(title=exc_title).exists():
Department.objects.create(title=exc_title)
return HttpResponse("上传成功")
5.手动新建一个excel表格depart.xlsx,并输入以下内容。

上传表格,选择文件后,点击上传。

文件上传后,显示"上传成功",则结束上传。

可以看到部门列表处新增了几个部门信息:

值得注意的是,如果你上传了空字段,页面会报错,但不要担心,咱们只需要针对为空的特殊情况做下if判断处理下就能解决,实现了Excel文件上传。接下来我们一起利用之前所学的Form和ModelForm的知识,实现一下图片上传,但是可能到了这里,许多朋友已经有些许生疏,那先快速回顾一下Form和ModelForm:
3、Form和ModelForm回顾
首先需要明确的是,在Django框架中,Form
和ModelForm
都是用来处理表单数据的,但它们各有特点和用途:
1.Form
- 定义 :
Form
是Django中用于生成和处理HTML表单的一个基础工具。它定义了表单的结构、数据类型和验证方式,但与数据库模型(models)无直接关联。 - 用途: 主要用于那些不直接与数据库模型对应的表单。例如,一个登录表单可能只需要用户名和密码字段,而不需要创建相应的数据库模型。
- 特点 :
- 可以手动定义表单字段。
- 包含数据验证功能,方便验证表单输入是否符合预期。
- 通过创建
forms.Form
子类来使用。
2.ModelForm
- 定义 :
ModelForm
是Django中的一个特殊的Form类,它直接基于模型(Model)自动生成表单字段 。ModelForm
会根据指定的模型自动创建表单字段,并且可以利用模型字段的定义来进行数据验证。 - 用途 : 主要用于需要与Django模型(数据库表)直接交互的场景。比如,当你需要创建或更新数据库记录时,
ModelForm
可以简化这一过程。 - 特点 :
- 自动生成表单字段,字段类型和验证规则继承自对应的模型字段。
- 简化了数据的保存过程,可以直接通过表单的
save()
方法保存或更新数据到数据库。 - 通过创建
forms.ModelForm
子类并设置其Meta
类的model
属性为对应的Django模型来使用。
3.使用场景比较
- 当你的表单数据需要直接与数据库交互(如创建、更新记录)时,使用
ModelForm
更方便,因为它减少了重复代码,并自动进行数据验证。 - 如果你的表单不对应数据库中的模型,或者你需要一个完全自定义的表单行为,那么使用
Form
会更灵活。
4.示例
1️⃣Form 示例
python
from django import forms
class ContactForm(forms.Form):
name = forms.CharField(label='Your name', max_length=100)
message = forms.CharField(widget=forms.Textarea)
2️⃣ModelForm 示例
python
from django import forms
from .models import Contact
class ContactForm(forms.ModelForm):
class Meta:
model = Contact
fields = ['name', 'email', 'message']
在ModelForm
的例子中,表单字段是基于Contact
模型自动生成的 ,而在Form
的例子中,每个字段都是手动定义的。
回顾了以上内容后,我们对Form和ModelForm的记忆应该又浮出水面了,接下来让我们来逐一用它们来实现图片上传,首先是Form上传。
4、Form图片上传
1.在urls.py 中上传列表的路径
upload/form/
,并告诉该路径指向的视图upload_from
python
import chart as chart
from django.urls import path
from api.views import depart, user, pretty, admin, account, task, order, chart, upload
urlpatterns = [
# 部门管理
path("depart/list/", depart.depart_list),
path("depart/add/", depart.depart_add),
path("depart/delete/", depart.depart_delete),
path("depart/<int:nid>/edit/", depart.depart_edit),
# 用户管理
path("user/list/", user.user_list),
path("user/add/", user.user_add),
path("user/model/form/add/", user.user_model_form_add),
path('user/<int:nid>/edit/', user.user_edit),
path("user/<int:nid>/delete/", user.user_delete),
# 靓号管理
path("pretty/list/", pretty.pretty_list),
path("pretty/add/", pretty.pretty_add),
path("pretty/<int:nid>/edit/", pretty.pretty_edit),
path("pretty/<int:nid>/delete/", pretty.pretty_delete),
# 管理员管理
path('admin/list/', admin.admin_list),
path('admin/add/', admin.admin_add),
path('admin/<int:nid>/edit/', admin.admin_edit),
path('admin/<int:nid>/delete/', admin.admin_delete),
path('admin/<int:nid>/reset/', admin.admin_reset),
# 用户登录
path('login/', account.login),
path('logout/', account.logout),
path('image/code/', account.image_code),
# 任务管理
path('task/list/', task.task_list),
path('task/ajax/', task.task_ajax),
path('task/add/', task.task_add),
# 订单管理
path('order/list/', order.order_list),
path('order/add/', order.order_add),
path('order/delete/', order.order_delete),
path('order/detail/', order.order_detail),
path('order/edit/', order.order_edit),
# 数据统计
path('chart/list/', chart.chart_list),
path('chart/bar/', chart.chart_bar),
path('chart/pie/', chart.chart_pie),
path('chart/line/', chart.chart_line),
# 文件上传
path('upload/list/', upload.upload_list),
path('depart/multi/', depart.depart_multi),
path('upload/form/', upload.upload_form),
]
2.修改upload.py,在其中添加上传图片的类与视图。
python
from django import forms
from django.shortcuts import render, HttpResponse
from api.utils.bootstrap import BootStrapForm
def upload_list(request):
# GET方法主要用于获取信息,而POST方法则用于提交数据
if request.method == "GET":
return render(request, "upload_list.html") # render函数负责将HTML模板渲染成最终的网页,并将这个网页返回给客户端。
# 声明图片的对象
file_object = request.FILES.get("avatar")
# 分块进行存储
# file_object.name 意思是图片上传前后保持原名称
f = open(file_object.name, mode='wb')
for chunk in file_object.chunks():
f.write(chunk)
f.close()
return HttpResponse("上传成功")
class UpForm(BootStrapForm):
name = forms.CharField(label="姓名")
age = forms.IntegerField(label="年龄")
img = forms.FileField(label="头像")
def upload_form(request):
"""上传图片"""
title = "Form上传"
form = UpForm()
return render(request, 'upload_form.html', {"form": form, "title": title})
3.在templates目录下新建upload_form.html
upload_form.html
html
{% extends 'layout.html' %}
{% block content %}
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{{ title }}</h3>
</div>
<div class="panel-body">
<form method="post" enctype="multipart/form-data" novalidate>
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label>{{ field.label }}: </label>
{{ field }}
<!-- 数据校验,显示错误信息 -->
<span style="color: red;">{{ field.errors.0 }}</span>
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">保存</button>
</form>
</div>
</div>
</div>
{% endblock %}
</body>
</html>
效果:

看到了上图实现的效果,但是这个框似乎有些不太妥当,因此我们对其做进一步的处理。
4.修改utils.py目录下的bootstrap.py。
python
# -*- coding: utf-8 -*-
# @Time : 2024-03-13 21:22
from django import forms
class BootStrapModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环ModelForm中的所有字段,给每个字段的插件设置
for name, field in self.fields.items():
# 字段中有属性,保留原来的属性,没有属性,才增加。
if field.widget.attrs:
field.widget.attrs["class"] = "form-control"
field.widget.attrs["placeholder"] = field.label
else:
field.widget.attrs = {
"class": "form-control",
"placeholder": field.label
}
class BootStrapForm(forms.Form):
bootstrap_exclude_fields = ['img']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环ModelForm中的所有字段,给每个字段的插件设置
for name, field in self.fields.items():
if name in self.bootstrap_exclude_fields:
continue
# 字段中有属性,保留原来的属性,没有属性,才增加
if field.widget.attrs:
field.widget.attrs["class"] = "form-control"
else:
field.widget.attrs = {
"class": "form-control",
}
效果:

到这里问题就解决了,接下来继续实现图片上传。
在 Django 的开发中一般要有两个特殊的文件夹:
- static: 存放静态文件
- media:存放用户上传的数据
static我们已然有了,但是media,我们还没有,需要进行一些配置。
5.修改urls.py,配置media路径。
python
import chart as chart
from django.conf import settings
from django.urls import path, re_path
from django.views.static import serve
from api.views import depart, user, pretty, admin, account, task, order, chart, upload
urlpatterns = [
# media配置
re_path(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}, name='media'),
# 部门管理
path("depart/list/", depart.depart_list),
path("depart/add/", depart.depart_add),
path("depart/delete/", depart.depart_delete),
path("depart/<int:nid>/edit/", depart.depart_edit),
# 用户管理
path("user/list/", user.user_list),
path("user/add/", user.user_add),
path("user/model/form/add/", user.user_model_form_add),
path('user/<int:nid>/edit/', user.user_edit),
path("user/<int:nid>/delete/", user.user_delete),
# 靓号管理
path("pretty/list/", pretty.pretty_list),
path("pretty/add/", pretty.pretty_add),
path("pretty/<int:nid>/edit/", pretty.pretty_edit),
path("pretty/<int:nid>/delete/", pretty.pretty_delete),
# 管理员管理
path('admin/list/', admin.admin_list),
path('admin/add/', admin.admin_add),
path('admin/<int:nid>/edit/', admin.admin_edit),
path('admin/<int:nid>/delete/', admin.admin_delete),
path('admin/<int:nid>/reset/', admin.admin_reset),
# 用户登录
path('login/', account.login),
path('logout/', account.logout),
path('image/code/', account.image_code),
# 任务管理
path('task/list/', task.task_list),
path('task/ajax/', task.task_ajax),
path('task/add/', task.task_add),
# 订单管理
path('order/list/', order.order_list),
path('order/add/', order.order_add),
path('order/delete/', order.order_delete),
path('order/detail/', order.order_detail),
path('order/edit/', order.order_edit),
# 数据统计
path('chart/list/', chart.chart_list),
path('chart/bar/', chart.chart_bar),
path('chart/pie/', chart.chart_pie),
path('chart/line/', chart.chart_line),
# 文件上传
path('upload/list/', upload.upload_list),
path('depart/multi/', depart.depart_multi),
path('upload/form/', upload.upload_form),
]
6.修改settings.py,添加media根目录和路径

python
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
MEDIA_URL = "/media/"
接下来实现
7.在api目录下新建media目录。

8.修改models.py,添加Boss数据表
python
class Boss(models.Model):
""" Boss """
name = models.CharField(verbose_name="姓名", max_length=32)
age = models.IntegerField(verbose_name="年龄")
img = models.CharField(verbose_name="头像", max_length=128)
之后进行数据库迁移,生成数据库表
cmd
python manage.py makemigrations
python manage.py migrate

运行本地服务器,进行项目测试:
cmd
python manage.py runserver

python
from django import forms
from django.shortcuts import render, HttpResponse
from api.models import Boss
from api.utils.bootstrap import BootStrapForm
import os
def upload_list(request):
# GET方法主要用于获取信息,而POST方法则用于提交数据
if request.method == "GET":
return render(request, "upload_list.html") # render函数负责将HTML模板渲染成最终的网页,并将这个网页返回给客户端。
# 声明图片的对象
file_object = request.FILES.get("avatar")
# 分块进行存储
# file_object.name 意思是图片上传前后保持原名称
f = open(file_object.name, mode='wb')
for chunk in file_object.chunks():
f.write(chunk)
f.close()
return HttpResponse("上传成功")
class UpForm(BootStrapForm):
name = forms.CharField(label="姓名")
age = forms.IntegerField(label="年龄")
img = forms.FileField(label="头像")
from django.conf import settings
def upload_form(request):
""" 上传图片 """
title = "Form上传"
if request.method == "GET":
form = UpForm()
return render(request, 'upload_form.html', {"form": form, "title": title})
form = UpForm(data=request.POST, files=request.FILES)
if form.is_valid():
# {'name': '张三', 'age': 21, 'img': <InMemoryUploadedFile: code.png (image/png)>}
# 1.读取图片内容,写入到文件夹中并获取文件的路径
image_object = form.cleaned_data.get("img")
# media_path = os.path.join(settings.MEDIA_ROOT, image_object.name)
media_path = os.path.join('media', image_object.name)
f = open(media_path, mode="wb")
for chunk in image_object.chunks():
f.write(chunk)
f.close()
# 2.将图片文件路径写入数据库
Boss.objects.create(
name=form.cleaned_data['name'],
age=form.cleaned_data['age'],
img=media_path,
)
return HttpResponse('ok')
return render(request, 'upload_form.html', {"form": form, "title": title})
效果:


可以看到图片已经上传到咱们本地的media目录下了。

同时咱们也可以查看数据表,可以看到信息也记录到了数据库里。

到了这里Form上传图片就基本完成了,接下来咱们再一起尝试用ModelForm实现图片上传。
5、ModelForm图片上传(推荐)
1.数据准备,在models.py中创建一个"城市"数据表。
python
class City(models.Model):
""" 城市 """
name = models.CharField(verbose_name="城市", max_length=32)
count = models.IntegerField(verbose_name="人口")
img = models.FileField(verbose_name="Logo", max_length=128, upload_to='city/')
之后进行数据库迁移,生成数据库表
cmd
python manage.py makemigrations
python manage.py migrate

运行本地服务器,进行项目测试:
cmd
python manage.py runserver
2.修改bootstrap.py
python
# -*- coding: utf-8 -*-
# @Time : 2024-03-13 21:22
from django import forms
class BootStrap:
bootstrap_exclude_fields = []
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环ModelForm中的所有字段,给每个字段的插件设置
for name, field in self.fields.items():
if name in self.bootstrap_exclude_fields:
continue
# 字段中有属性,保留原来的属性,没有属性,才增加。
if field.widget.attrs:
field.widget.attrs["class"] = "form-control"
field.widget.attrs["placeholder"] = field.label
else:
field.widget.attrs = {
"class": "form-control",
"placeholder": field.label
}
class BootStrapModelForm(BootStrap, forms.ModelForm):
pass
class BootStrapForm(forms.Form):
bootstrap_exclude_fields = ['img']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环ModelForm中的所有字段,给每个字段的插件设置
for name, field in self.fields.items():
if name in self.bootstrap_exclude_fields:
continue
# 字段中有属性,保留原来的属性,没有属性,才增加
if field.widget.attrs:
field.widget.attrs["class"] = "form-control"
else:
field.widget.attrs = {
"class": "form-control",
}
3.修改upload.py
python
from django import forms
from django.shortcuts import render, HttpResponse
from api.models import Boss, City
from api.utils.bootstrap import BootStrapForm, BootStrapModelForm
import os
def upload_list(request):
# GET方法主要用于获取信息,而POST方法则用于提交数据
if request.method == "GET":
return render(request, "upload_list.html") # render函数负责将HTML模板渲染成最终的网页,并将这个网页返回给客户端。
# 声明图片的对象
file_object = request.FILES.get("avatar")
# 分块进行存储
# file_object.name 意思是图片上传前后保持原名称
f = open(file_object.name, mode='wb')
for chunk in file_object.chunks():
f.write(chunk)
f.close()
return HttpResponse("上传成功")
class UpForm(BootStrapForm):
name = forms.CharField(label="姓名")
age = forms.IntegerField(label="年龄")
img = forms.FileField(label="头像")
from django.conf import settings
def upload_form(request):
""" 上传图片 """
title = "Form上传"
if request.method == "GET":
form = UpForm()
return render(request, 'upload_form.html', {"form": form, "title": title})
form = UpForm(data=request.POST, files=request.FILES)
if form.is_valid():
# {'name': '张三', 'age': 21, 'img': <InMemoryUploadedFile: code.png (image/png)>}
# 1.读取图片内容,写入到文件夹中并获取文件的路径
image_object = form.cleaned_data.get("img")
# media_path = os.path.join(settings.MEDIA_ROOT, image_object.name)
media_path = os.path.join('media', image_object.name)
f = open(media_path, mode="wb")
for chunk in image_object.chunks():
f.write(chunk)
f.close()
# 2.将图片文件路径写入数据库
Boss.objects.create(
name=form.cleaned_data['name'],
age=form.cleaned_data['age'],
img=media_path,
)
return HttpResponse('ok')
return render(request, 'upload_form.html', {"form": form, "title": title})
class UpModelForm(BootStrapModelForm):
bootstrap_exclude_fields = ['img']
class Meta:
model = City
fields = "__all__"
def upload_model_form(request):
""" 上传文件和数据 """
title = "ModelForm上传文件"
if request.method == "GET":
form = UpModelForm()
return render(request, 'upload_form.html', {"form": form, "title": title})
form = UpModelForm(data=request.POST, files=request.FILES)
if form.is_valid():
# 对于文件会自动保存
# 目录信息会自动保存至数据库中
form.save()
return HttpResponse("success!")
return render(request, 'upload_form.html', {"form": form, "title": title})
4.修改urls.py ,添加图片上传列表的路径
upload/model/form/
,并告诉该路径指向的视图upload_model_form
python
import chart as chart
from django.conf import settings
from django.urls import path, re_path
from django.views.static import serve
from api.views import depart, user, pretty, admin, account, task, order, chart, upload
urlpatterns = [
# media配置
re_path(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}, name='media'),
# 部门管理
path("depart/list/", depart.depart_list),
path("depart/add/", depart.depart_add),
path("depart/delete/", depart.depart_delete),
path("depart/<int:nid>/edit/", depart.depart_edit),
# 用户管理
path("user/list/", user.user_list),
path("user/add/", user.user_add),
path("user/model/form/add/", user.user_model_form_add),
path('user/<int:nid>/edit/', user.user_edit),
path("user/<int:nid>/delete/", user.user_delete),
# 靓号管理
path("pretty/list/", pretty.pretty_list),
path("pretty/add/", pretty.pretty_add),
path("pretty/<int:nid>/edit/", pretty.pretty_edit),
path("pretty/<int:nid>/delete/", pretty.pretty_delete),
# 管理员管理
path('admin/list/', admin.admin_list),
path('admin/add/', admin.admin_add),
path('admin/<int:nid>/edit/', admin.admin_edit),
path('admin/<int:nid>/delete/', admin.admin_delete),
path('admin/<int:nid>/reset/', admin.admin_reset),
# 用户登录
path('login/', account.login),
path('logout/', account.logout),
path('image/code/', account.image_code),
# 任务管理
path('task/list/', task.task_list),
path('task/ajax/', task.task_ajax),
path('task/add/', task.task_add),
# 订单管理
path('order/list/', order.order_list),
path('order/add/', order.order_add),
path('order/delete/', order.order_delete),
path('order/detail/', order.order_detail),
path('order/edit/', order.order_edit),
# 数据统计
path('chart/list/', chart.chart_list),
path('chart/bar/', chart.chart_bar),
path('chart/pie/', chart.chart_pie),
path('chart/line/', chart.chart_line),
# 文件上传
path('upload/list/', upload.upload_list),
path('depart/multi/', depart.depart_multi),
path('upload/form/', upload.upload_form),
path('upload/model/form/', upload.upload_model_form),
]
5.修改layout.html

layout.html
html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--Bootstrap框架-->
<link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'plugins/font-awesome-4.7.0/css/font-awesome.css' %}">
<!--datetimepicker插件-->
<link rel="stylesheet" type="text/css"
href="{% static 'plugins/bootstrap-datetimepicker/css/bootstrap-datetimepicker.css' %}">
{% block css %}
<style>
.navbar {
border-radius: 0;
}
</style>
{% endblock %}
</head>
<body>
<nav class="navbar navbar-default">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">用户管理系统</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li><a href="/admin/list">管理员账户</a></li>
<li><a href="/depart/list">部门管理</a></li>
<li><a href="/user/list">用户管理</a></li>
<li><a href="/pretty/list">靓号管理</a></li>
<li><a href="/task/list">任务管理</a></li>
<li><a href="/order/list">订单管理</a></li>
<li><a href="/chart/list">数据统计</a></li>
<li><a href="/upload/list/">上传文件</a></li>
</ul>
<ul class="nav navbar-nav">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">上传<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="/upload/list/">上传图片</a></li>
<li><a href="/upload/form/">Form上传图片</a></li>
<li><a href="/upload/model/form/">ModelForm上传图片</a></li>
</ul>
</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="/login">登录</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">{{ request.session.info.name }}<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">个人资料</a></li>
<li><a href="#">我的信息</a></li>
<li role="separator" class="divider"></li>
<li><a href="/logout/">注销</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<div>
<div class="container">
{% block content %}{% endblock %}
</div>
</div>
<script src="{% static 'js/jquery.min.js' %}"></script>
<!-- 加载 Bootstrap DateTimePicker JS -->
<script src="{% static 'plugins/bootstrap-3.4.1/js/bootstrap.js' %}"></script>
<script src="{% static 'plugins/bootstrap-datetimepicker/js/bootstrap-datetimepicker.min.js' %}"></script>
<script src="{% static 'plugins/bootstrap-datetimepicker/js/locales/bootstrap-datetimepicker.zh-CN.js' %}"></script>
<script type="text/javascript">
$(function () {
//当容器加载完成,对容器调用工具函数
$("#dt").datetimepicker({
language: 'zh-CN', //语言
format: 'yyyy-mm-dd',//日期的格式
minView: 'month', //可以选择的最小视图
initialDate: new Date(),//初始化显示的日期
autoclose: true,//设置选择完日期或者时间之后,日否自动关闭日历
todayBtn: true,//设置自动显示为今天
clearBtn: false//设置是否清空按钮,默认为false
});
});
</script>
{% block js %}
{% endblock %}
效果:


浏览器进行响应:

查看media目录,可以看到创建了city目录,并上传了图片。

可以看到数据库中也存储了相应信息。

上面的内容,咱们已经学会了如何实现上传文件,但是没有具体的案例实践,掌握还是比较难的,因此咱们举一个简单的例子来应用一下咱们上述所学。
6、城市管理
1.修改urls.py ,添加城市管理列表的路径
city/list/和city/add/
,并告诉该路径指向的视图city_list与city_add
python
import chart as chart
from django.conf import settings
from django.urls import path, re_path
from django.views.static import serve
from api.views import depart, user, pretty, admin, account, task, order, chart, upload
urlpatterns = [
# media配置
re_path(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}, name='media'),
# 部门管理
path("depart/list/", depart.depart_list),
path("depart/add/", depart.depart_add),
path("depart/delete/", depart.depart_delete),
path("depart/<int:nid>/edit/", depart.depart_edit),
# 用户管理
path("user/list/", user.user_list),
path("user/add/", user.user_add),
path("user/model/form/add/", user.user_model_form_add),
path('user/<int:nid>/edit/', user.user_edit),
path("user/<int:nid>/delete/", user.user_delete),
# 靓号管理
path("pretty/list/", pretty.pretty_list),
path("pretty/add/", pretty.pretty_add),
path("pretty/<int:nid>/edit/", pretty.pretty_edit),
path("pretty/<int:nid>/delete/", pretty.pretty_delete),
# 管理员管理
path('admin/list/', admin.admin_list),
path('admin/add/', admin.admin_add),
path('admin/<int:nid>/edit/', admin.admin_edit),
path('admin/<int:nid>/delete/', admin.admin_delete),
path('admin/<int:nid>/reset/', admin.admin_reset),
# 用户登录
path('login/', account.login),
path('logout/', account.logout),
path('image/code/', account.image_code),
# 任务管理
path('task/list/', task.task_list),
path('task/ajax/', task.task_ajax),
path('task/add/', task.task_add),
# 订单管理
path('order/list/', order.order_list),
path('order/add/', order.order_add),
path('order/delete/', order.order_delete),
path('order/detail/', order.order_detail),
path('order/edit/', order.order_edit),
# 数据统计
path('chart/list/', chart.chart_list),
path('chart/bar/', chart.chart_bar),
path('chart/pie/', chart.chart_pie),
path('chart/line/', chart.chart_line),
# 文件上传
path('upload/list/', upload.upload_list),
path('depart/multi/', depart.depart_multi),
path('upload/form/', upload.upload_form),
path('upload/model/form/', upload.upload_model_form),
# 城市管理
path('city/list/', city.city_list),
path('city/add/', city.city_add),
]
2.在views目录下新建city.py
py
from api.utils.bootstrap import BootStrapModelForm
from django.shortcuts import render, redirect
from api.models import City
from api.utils.pagination import Pagination
def city_list(request):
""" 城市列表 """
data_dict = {}
# 如果是空字典,表示获取所有
# 不加后面的 "", 首次访问浏览器,搜索框中不会显示前端页面中的 placeholder="Search for..." 属性
search_data = request.GET.get('query', "")
if search_data:
data_dict["name__contains"] = search_data
queryset = City.objects.filter(**data_dict).order_by("-count")
### 引入封装的 Pagination 类并初始化
# 初始化
page_object = Pagination(request, queryset, page_size=10, page_param="page")
page_queryset = page_object.page_queryset
# 调用对象的html方法,生成页码
page_object.html()
page_string = page_object.page_string
context = {
"page_queryset": page_queryset, # 分页的数据
"search_data": search_data, # 搜索的内容
"page_string": page_string, # 页码
}
return render(request, 'city_list.html', context)
class UpModelForm(BootStrapModelForm):
bootstrap_exclude_fields = ['img']
class Meta:
model = City
fields = "__all__"
def city_add(request):
""" 新建城市 """
if request.method == "GET":
form = UpModelForm()
return render(request, 'upload_form.html', {"form": form})
form = UpModelForm(data=request.POST, files=request.FILES)
if form.is_valid():
# 对于文件会自动保存
# 目录信息会自动保存至数据库中
form.save()
return redirect('/city/list/')
return render(request, 'upload_form.html', {"form": form})
3.在templates目录下新建city_list.html
city_list.html
html
{% extends 'layout.html' %}
{% block content %}
<div class="container">
<div style="margin-bottom: 10px">
<a class="btn btn-primary" href="/city/add/" target="_blank">新建城市</a>
<div style="float: right; width: 300px;">
<form method="get">
<div class="input-group">
<input type="text" name="query" class="form-control" placeholder="Search for..."
value="{{ search_data }}">
<span class="input-group-btn">
<button class="btn btn-default" type="submit">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
</button>
</span>
</div>
</form>
</div>
</div>
<div>
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list" aria-hidden="true" style="margin-right: 5px;"></span>
<span>部门列表</span>
</div>
<!-- Table -->
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>Logo</th>
<th>名称</th>
<th>人口</th>
</tr>
</thead>
<tbody>
{% for obj in page_queryset %}
<tr>
<th>{{ obj.id }}</th>
<td>
<img src="/media/{{ obj.img }}" style="height: 60px;">
</td>
<td>{{ obj.name }}</td>
<td>{{ obj.count }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<ul class="pagination">
{{ page_string }}
</ul>
</div>
{% endblock %}
4.修改layout.html,加入城市管理列表。

html
<li><a href="/city/list/">城市管理</a></li>
效果:


系统整体效果:

至此Python Web开发的内容就到此落下帷幕了,以上实现的系统,界面或许比较简单,但是基本覆盖了常用的各类功能,以后在此思路之上进行拓展,系统会更加完善。前方道路漫漫,这只是短暂的旅程,未来尚有许多前景,加油!
很感谢你能看到这里,如有相关疑问,还请下方评论留言。
Code_流苏(CSDN) (一个喜欢古诗词和编程的Coder😊)
希望本篇内容能对大家有所帮助,如果大家喜欢的话,请动动手点个赞和关注吧,非常感谢你们的支持!