当前位置:首页 > 技术 > 正文内容

Django开发实战:快速构建简易图片管理应用

访客 技术 2026年7月8日 1

初次接触Django框架,按照官方文档的指引走了一遍入门示例。作为一个标准的MVC架构框架,如果对MVC模式还不熟悉的话,建议先查阅相关资料进行了解。

Django项目创建、数据库迁移等基础操作官方文档中都有详细说明。本文演示环境采用Django 2.1版本配合Python 3.6,主要实现一个最简单的图片管理功能,包含数据的增删操作。

环境准备与项目创建

首先安装Django框架:

pip install django

创建新的Django项目:

django-admin startproject mysite

项目创建完成后,会自动生成一系列文件。关于各个文件的用途,官方文档中有详细的解释说明,这里就不再赘述。

数据库配置

由于开发机上的MySQL服务部署在另一台虚拟机上,所以在settings.py中需要调整数据库连接配置:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'djangodb',
        'HOST': '192.168.175.130',
        'USER': 'root',
        'PASSWORD': '123456',
        'CHARSET': 'utf8mb4',
    }
}

模型定义

创建应用并定义数据模型:

# myadmin/models.py
class ImageRecord(models.Model):
    resource_id = models.IntegerField()
    image_url = models.CharField(max_length=255)
    category_id = models.SmallIntegerField()
    image_title = models.CharField(max_length=255)
    description = models.TextField()

    def __str__(self):
        return self.image_title

配置应用:

# myadmin/apps.py
class MyadminConfig(AppConfig):
    name = 'myadmin'

在settings.py中注册应用:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog.apps.BlogConfig',
    'myadmin.apps.MyadminConfig',
]

数据库迁移

执行数据迁移命令,生成建表语句:

manage.py makemigrations myadmin

该命令会根据模型定义生成相应的数据库表结构。

执行迁移:

manage.py migrate

此时会创建所需的数据库表。

MySQL驱动问题

初次执行迁移命令时,发现缺少MySQL驱动库。原本计划安装python-mysql,但尝试后发现该库与Python 3.6不兼容。最终选择使用PyMySQL代替,并在settings.py中添加如下配置:

import os
import pymysql

pymysql.install_as_MySQLdb()

配置完成后,数据库迁移正常工作。

视图函数实现

定义视图处理函数:

# myadmin/views.py
from django.shortcuts import render
from django.http import HttpResponse, Http404, HttpResponseRedirect, JsonResponse
from django.urls import reverse
from .models import ImageRecord
import os
import uuid


def home(request):
    return HttpResponse('欢迎访问管理后台')


def image_list(request):
    images = ImageRecord.objects.all()
    context = {"image_data": images}
    return render(request, 'gallery/index.html', context)


def image_create(request):
    resource_id = request.POST.get('rid', None)
    category_id = request.POST.get('cid', None)
    title = request.POST.get('title', None)
    description = request.POST.get('backup', None)

    url = save_upload(request.FILES['img'])

    new_image = ImageRecord(
        resource_id=resource_id,
        category_id=category_id,
        image_title=title,
        description=description,
        image_url=url
    )
    new_image.save()
    
    if new_image.id is None:
        raise Http404
    return HttpResponseRedirect(reverse('myadmin:image_list'))


def image_delete(request):
    img_id = request.POST.get('id', None)
    if img_id is None:
        return JsonResponse({'status': 0})
    try:
        image = ImageRecord.objects.get(pk=img_id)
        image.delete()
    except Exception as e:
        return JsonResponse({'status': 0})
    else:
        return JsonResponse({'status': 1})


def save_upload(f):
    upload_dir = '/images/'
    base_url = 'http://127.0.0.1:81/'
    if not os.path.exists(upload_dir):
        os.mkdir(upload_dir)
    filename = str(uuid.uuid1()) + f.name
    filepath = upload_dir + filename
    with open(filepath, 'wb+') as dest:
        for chunk in f.chunks():
            dest.write(chunk)
    return base_url + filename

URL路由配置

# myadmin/urls.py
from django.urls import path
from . import views

app_name = 'myadmin'
urlpatterns = [
    path('', views.home, name='home'),
    path('images/list', views.image_list, name='image_list'),
    path('images/create', views.image_create, name='image_create'),
    path('images/delete', views.image_delete, name='image_delete')
]

模板页面

<!doctype html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图片管理</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap-theme.min.css">
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
    <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <style>
        .header-bar { background-color: aqua; }
        .sidebar { background-color: #fff; }
    </style>
</head>
<body>
<div class="container-fluid">
    <div class="row">
        <div class="col-md-12 header-bar">
            <p>管理系统</p>
        </div>
        <div class="col-md-2 sidebar">
            <p>导航栏</p>
        </div>
        <div class="col-md-10">
            <div class="row">
                <button type="button" class="btn btn-primary btn-sm" data-toggle="modal" data-target="#addModal">
                    新增图片
                </button>
            </div>
            
            <!-- 添加弹窗 -->
            <div class="modal fade" id="addModal" tabindex="-1" role="dialog">
                <div class="modal-dialog" role="document">
                    <div class="modal-content">
                        <div class="modal-header">
                            <button type="button" class="close" data-dismiss="modal"><span>&times;</span></button>
                            <h4 class="modal-title">添加图片</h4>
                        </div>
                        <div class="modal-body">
                            <form id="imageForm" class="form-horizontal" action="{% url 'myadmin:image_create' %}"
                                  method="post" enctype="multipart/form-data">
                                <input type="hidden" name="rid" value="1">
                                <input type="hidden" name="cid" value="1">
                                {% csrf_token %}
                                <div class="form-group">
                                    <label class="col-sm-2 control-label">标题</label>
                                    <div class="col-sm-10">
                                        <input type="text" class="form-control" name="title">
                                    </div>
                                </div>
                                <div class="form-group">
                                    <label class="col-sm-2 control-label">描述</label>
                                    <div class="col-sm-10">
                                        <input type="text" class="form-control" name="backup">
                                    </div>
                                </div>
                                <div class="form-group">
                                    <label class="col-sm-2 control-label">图片文件</label>
                                    <div class="col-sm-10">
                                        <input type="file" class="form-control" name="img">
                                    </div>
                                </div>
                            </form>
                        </div>
                        <div class="modal-footer">
                            <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
                            <button type="button" class="btn btn-primary" id="submitBtn">保存</button>
                        </div>
                    </div>
                </div>
            </div>
            
            <!-- 数据表格 -->
            <div class="row" style="margin-top: 20px;">
                | 资源ID | 标题 | 分类ID | 描述 | 图片 | 操作 |
|---|---|---|---|---|---|
| {{item.resource\_id}} | {{item.image\_title}} | {{item.category\_id}} | {{item.description}} | ![]({{item.image_url}}) | <button class="btn btn-danger delete-btn" data-id="{{item.id}}">删除</button> |
            </div>
        </div>
    </div>
</div>

<script>
    $('#submitBtn').click(function () {
        $('#imageForm').submit();
    });
    
    $('.delete-btn').click(function () {
        var btn = $(this);
        var imgId = btn.attr('data-id');
        var csrfToken = jQuery("[name=csrfmiddlewaretoken]").val();
        
        $.ajax({
            beforeSend: function (xhr, settings) {
                xhr.setRequestHeader("X-CSRFToken", csrfToken);
            },
            url: "{% url 'myadmin:image_delete' %}",
            data: {id: imgId},
            type: 'post',
            dataType: 'json',
            success: function (response) {
                if (response.status === 1) {
                    alert('删除成功');
                } else {
                    alert('删除失败');
                }
                location.reload();
            }
        });
    });
</script>
</body>
</html>

字符集问题处理

在实际测试过程中,遇到一个编码相关的错误:

1366, "Incorrect string value: '\\xE6\\xB5\\x8B\\xE8\\xAF\\x95' for column 'title' at row 1"

排查发现MySQL数据库默认字符集配置为latin1,导致中文字符无法正常存储。通过以下命令查看数据库字符集配置:

mysql> show variables like '%char%';

解决方案是将数据库和表的字符集统一修改为utf8mb4。关于具体的修改方法,可以参考MySQL字符集配置的相关文档。

修改完成后,中文数据即可正常插入。

小结

本示例实现了Django项目的完整搭建流程,包括数据库配置、模型定义、视图开发、模板渲染以及基本的增删操作。示例代码较为简洁,未做完善的异常处理,目前仅实现了数据的新增和删除功能。

整体使用感受:Django框架功能完备,但相对笨重,学习曲线较陡。接下来计划尝试一下Flask框架,看看是否能获得更轻便的开发体验。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。