尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

个人漫画管理网站怎么搭?Django数据建模、Admin后台与图片流式加载实战

发布时间:2026/9/14 9:35:32

资讯中心
01
ARTICLE

个人漫画管理网站怎么搭?Django数据建模、Admin后台与图片流式加载实战

个人漫画管理网站怎么搭?Django数据建模、Admin后台与图片流式加载实战
简介面向计算机相关专业学生与毕业生提供基于Django的个人漫画管理网站完整毕业设计项目。该资源覆盖网站前后端核心代码、配置与数据库相关文件适用于毕业设计、课程设计及项目初期演示。包体共54个文件、107KB包含18个Python源码文件承担后端逻辑5个HTML模板配合23个CSS与5个JS文件实现前端页面与交互同时附带README说明文档及项目配置辅助文件目录划分清晰便于二次开发与功能扩展。目前已有61人学习下载项目已在Windows 10/11及macOS环境下测试运行成功具备较高完成度。读者可从中获取完整项目源码、详细说明文档以及作者调试通过的环境配置进而理解Django MTV架构、模型设计、漫画数据抓取与静态资源组织等关键实现思路既可直接作为毕业设计原型也可在此基础上继续优化或增加个性化功能适合入门学习和实战参考。1. 当漫画文件夹多到要CtrlF个人漫画管理网站要解决的问题硬盘里积了三年漫画文件夹命名从《火影忍者》到“2024新番合集2”什么都有想找一部N年前看过的冷门作只能一层层点开缩略图碰运气。这是所有收藏型用户都撞过的墙。基于Django的个人漫画管理网站就是把散落在磁盘上的漫画图片目录清洗成带封面、作者、标签、阅读进度的在线漫画库后台用Django Admin维护元数据前台提供分类浏览和关键词搜索阅读页按需拉取单张图片而不整卷加载。它适合两类人——拿毕业设计练全栈链路的学生以及想给本地资源目录做一次正规化整理的开发者。整条链路浓缩成三个环节数据建模、后台录入、流式图片输出。下文按这三段展开中间穿插检索与进度标记的细节最后用一个你没怎么注意过的响应头收尾。2. Django项目初始化与漫画数据模型的三张表设计2.1 从venv到项目骨架Windows和Linux下都能跑通的启动顺序拿到题目先别急着写业务代码先确认环境。Python 3.10配Django 4.x是目前最稳的组合Python 3.12配Django 5.x也能用但第三方库兼容性需要现查。环境隔离用内置的venv不要图省事直接pip install到全局后面装Pillow、mysqlclient时版本冲突的概率会小很多。python -m venv venv source venv/bin/activate # Windows下用 venv\Scripts\activate pip install django pillow django-admin startproject comic_site . python manage.py startapp comic四条命令的逻辑分别是创建虚拟环境并激活Pillow是ImageField处理封面的硬依赖startproject后面的点让manage.py落在当前目录后续路径干净startapp生成comic应用目录。个人项目不强制拆分多个app把漫画、章节、进度都放在comic这一个app里迁移文件清晰答辩时也讲得明白。首次提交代码前记得把venv目录加进.gitignore。第2章Django项目初始化与漫画数据模型的三张表设计2.1.1 Python与Django版本组合建议组合方案适用场景注意事项Python 3.10 Django 4.2 LTS毕业设计主流选择mysqlclient和Pillow都有预编译包安装省心Python 3.12 Django 5.0想用最新特性部分第三方后台美化包可能未适配Windows Django开发服务器本地演示图片并发加载时性能明显弱于Linux我一般选表格里的第一种组合。Django 4.2是LTS版本安全更新周期长网上搜到的排错案例也最多Python 3.10对类型注解的支持已经够用没必要在环境上给自己增加变量。若是在Linux服务器上部署注意系统自带的Python可能是3.8需要用deadsnakes或编译安装单独的Python版本避免污染系统环境。2.2 Manga、Chapter、Page漫画领域的三个核心模型个人漫画管理网站的数据量不算大但关系层次必须清晰。参考主流漫画站的URL结构——/manga/1/chapter/2/page/3模型跟着这个路径拆成三张表。Manga承载封面、作者、状态、标签这些展示字段Chapter记录卷或话的标题和排序Page才是真正的图片实体一个Page对应磁盘上的一张漫画图字段最少但查询最频繁。from django.db import models from django.utils import timezone class Manga(models.Model): title models.CharField(漫画名, max_length120) author models.CharField(作者, max_length50, blankTrue) cover models.ImageField(封面, upload_tocovers/%Y/%m/) status models.CharField( 连载状态, max_length10, choices[(ongoing, 连载中), (finished, 已完结), (hiatus, 停更)], defaultongoing, ) tags models.CharField(标签, max_length200, blankTrue, help_text多个标签用逗号分隔) description models.TextField(简介, blankTrue) created_at models.DateTimeField(入库时间, defaulttimezone.now) class Meta: ordering [-created_at] verbose_name 漫画 def __str__(self): return self.title class Chapter(models.Model): manga models.ForeignKey(Manga, on_deletemodels.CASCADE, related_namechapters, verbose_name所属漫画) title models.CharField(章节标题, max_length120) chapter_no models.PositiveIntegerField(章节序号, default1) released_at models.DateField(发布日期, nullTrue, blankTrue) class Meta: ordering [chapter_no] unique_together (manga, chapter_no) verbose_name 章节 def __str__(self): return f{self.manga.title} 第{self.chapter_no}话 class Page(models.Model): chapter models.ForeignKey(Chapter, on_deletemodels.CASCADE, related_namepages, verbose_name所属章节) page_no models.PositiveIntegerField(页码, default1) image models.ImageField(漫画原图, upload_topages/%Y/%m/) class Meta: ordering [page_no] unique_together (chapter, page_no) verbose_name 页面图 def __str__(self): return f{self.chapter} 第{self.page_no}页这段代码有三个设计取舍值得展开。第一tags用逗号分隔的CharField而不是独立的多对多表——个人站长维护不了几十个标签的管理页逗号分隔配合icontains搜索已经够用第二unique_together保证同一漫画下章节序号不会重复批量导入时用update_or_create能做幂等写入第三upload_to按年月建子目录避免单目录文件过多拖慢文件系统索引。用户、进度这类字段目前刻意不放进来先让资源实体关系保持纯净后面挂进度表时用外键即可。2.3 迁移、超级用户与首条数据模型建完后先跑迁移再用createsuperuser创建后台账号。这个账号不是最后才建边建模边进admin核对显示效果比全部写完再回头排查高效得多。python manage.py makemigrations comic python manage.py migrate python manage.py createsuperuser迁移命令执行后应看到Create model Manga、Create model Chapter、Create model Page三条记录。若第2章2.2节里的外键字段名称在两次迁移之间发生过修改Django会提示删除旧外键并新建新外键此时直接选择1确认即可数据量小不涉及数据丢失风险。首条数据可以从admin录入也可以写一个from comic.models import Manga的数据脚本按JSON导入推荐后者——毕业设计要提交到GitHub或网盘附带一份JSON种子数据能让评审老师一键复现。3. 把后台管理做成能录入上千部漫画的样子Django Admin注册与界面美化后台不直接面对读者但维护体验直接影响你愿不愿意持续往里录数据。上百部漫画、上千个章节往Admin里塞的时候列表过滤、内联编辑和缩略图预览决定你录入一部的成本是分钟级还是小时级。这一章把后台操作压成三件事模型注册、内联编辑、皮肤美化。3.1 模型注册与list_display缩略图打开comic/admin.py先把三个模型注册进去再针对列表页做字段裁剪。默认注册只显示对象字符串排查数据时要一页页翻效率太低。from django.contrib import admin from django.utils.html import format_html from .models import Manga, Chapter, Page admin.register(Manga) class MangaAdmin(admin.ModelAdmin): list_display [cover_preview, title, author, status, chapter_count, created_at] list_filter [status, created_at] search_fields [title, author, tags] list_per_page 20 def cover_preview(self, obj): if obj.cover: return format_html(img src{} width48 styleobject-fit:cover;/, obj.cover.url) return 无封面 cover_preview.short_description 封面 def chapter_count(self, obj): return obj.chapters.count() chapter_count.short_description 章节数list_display里放函数列的好处是直接用Admin模板输出缩略图cover_preview返回format_html包装的Img标签比只显示图片路径直观得多。chapter_count会对每行执行一次COUNT查询个人站几十部漫画时性能无感若库量过千需要改成annotate聚合避免N1查询。list_filter按状态和入库时间过滤收录还在更新的作品时三秒就能定位到ongoing的条目。3.2 用内联编辑加快章节录入新建漫画后马上要补十几话的章节信息如果用默认列表页一话一存费时且容易漏。Django Admin提供InlineModelAdmin可以把Chapter编辑嵌进Manga的编辑页底部。class ChapterInline(admin.TabularInline): model Chapter extra 1 admin.register(Manga) class MangaAdmin(admin.ModelAdmin): list_display [cover_preview, title, author, status, chapter_count, created_at] list_filter [status, created_at] search_fields [title, author, tags] list_per_page 20 inlines [ChapterInline]Page模型不建议内联到Chapter编辑页——一个章节几十页图片全部铺开会拖垮Admin页面渲染而且上传图片时浏览器要同时发几十个请求开发服务器容易卡死。Page的管理页保持独立只保留chapter选择框、page_no、image三个字段按章节和页码排序后勾选批量修改。这是很多教程没讲的边界内联适合行数少的从表图片类从表用独立管理页。3.3 admin界面美化的两条路线Jazzmin还是纯CSS覆写Django原生Admin能用但谈不上好看毕业设计答辩时界面观感会直接影响印象分。美化方案有两个主流路线方案优点缺点django-jazzmin安装即用主题多支持自定义Logo和侧边栏折叠多一个依赖Django升级时需同步跟进纯CSS覆写无额外依赖改base_site.html和CSS需要理解Admin模板继承链维护成本高个人项目我选django-jazzmin装好后把jazzmin放到INSTALLED_APPS里django.contrib.admin前面再执行python manage.py collectstatic把静态文件收集到位。顺序不能反否则Django会优先使用原生的Admin静态文件美化不生效。如果不想引入依赖改用覆写base_site.html的方式也能达到效果。需要理解Admin模板继承链适合对Django模板机制想加深理解的人。4. 前台浏览、关键词搜索与阅读进度的存储设计后台负责录入前台负责被用。个人漫画站不必做成在线漫画平台那样的推荐流重点就三块列表能搜索、详情能看简介、阅读页能翻章节。再加一个只有登录用户才有意义的进度标记。这章按这三个视图展开最后落到进度表的存储设计。4.1 列表页与搜索一个ListView处理关键词列表页用Django自带的ListView省去手写分页逻辑。搜索参数从GET的q字段取用Q对象把标题、作者、标签三个字段一次性命中。from django.views.generic import ListView from django.db.models import Q from .models import Manga class MangaListView(ListView): model Manga template_name comic/manga_list.html context_object_name mangas paginate_by 24 def get_queryset(self): qs super().get_queryset() keyword self.request.GET.get(q, ).strip() if keyword: qs qs.filter( Q(title__icontainskeyword) | Q(author__icontainskeyword) | Q(tags__icontainskeyword) ) return qspaginate_by 24配合4x6网格的卡片布局PC端和手机端都能显示得比较均匀。icontains在SQLite和MySQL下分别展开成LIKE %keyword%个人站的千级数据量完全不需要全文索引这是故意不过度设计的地方。模板里分页链接用request.GET.urlencode保留住q参数否则翻到第二页搜索条件就丢了。4.2 阅读页相邻章节查询与页面顺序输出阅读页是用户停留时间最长的页面需要一次查询带出页面列表、上一章、下一章三个数据集让翻页时不用退回章节列表重新选择。from django.shortcuts import get_object_or_404, render from .models import Manga, Chapter def reader(request, manga_id, chapter_no): manga get_object_or_404(Manga, pkmanga_id) chapter get_object_or_404( Chapter, mangamanga, chapter_nochapter_no ) pages chapter.pages.all() prev_chapter Chapter.objects.filter( mangamanga, chapter_no__ltchapter_no ).order_by(-chapter_no).first() next_chapter Chapter.objects.filter( mangamanga, chapter_no__gtchapter_no ).order_by(chapter_no).first() context { manga: manga, chapter: chapter, pages: pages, prev_chapter: prev_chapter, next_chapter: next_chapter, } return render(request, comic/reader.html, context)两次chapter_no__lt/__gt查询比遍历Chapter列表高效.first()取最近的一条就能完成相邻章节导航。模板里翻页链接直接用manga_id和chapter_no拼接URL设计保持和模型三层结构一致。页面图片循环输出时用forloop.counter作为img的序号不直接依赖数据库里的page_no因为批量导入时页号偶尔会断档错位直接透到用户端会很难排查。4.3 阅读进度表只记录停在第几话进度表的设计原则是够用就好。只记录用户最后读到的chapter_no没有必要存page_no——用户翻页是连续场景断点恢复到章节级已经足够快记页码会让每次翻页都触发一次UPDATE。from django.db import models class ReadingProgress(models.Model): user models.ForeignKey(auth.User, on_deletemodels.CASCADE, verbose_name用户) manga models.ForeignKey(Manga, on_deletemodels.CASCADE, related_namereading_progress, verbose_name漫画) chapter_no models.PositiveIntegerField(读到第几话, default1) updated_at models.DateTimeField(更新时间, auto_nowTrue) class Meta: unique_together (user, manga) verbose_name 阅读进度每次阅读页渲染时调用update_or_create按(user, manga)更新单行记录ReadingProgress.objects.update_or_create( userrequest.user, mangamanga, defaults{chapter_no: chapter_no} )列表页要展示“读到第x话”时对查询集执行prefetch_related(reading_progress)否则N部漫画会触发N条额外查询这是答辩时面试官最爱的提问点之一。在列表页里把这个数字显示成“读到第3话 / 共12话”的小字整个管理系统的完整性一下子就体现出来了。5. 图片按需加载StreamingHttpResponse替代MEDIA_URL直接暴露5.1 为什么个人漫画库不该直接暴露MEDIA_URLMEDIA_URL直接拼图片路径是Django入门最常用的方式开发环境一切正常但个人漫画管理网站放上服务器后会出现两个问题。第一图片以万为单位存放在已有目录全部复制进MEDIA_ROOT既不现实也会让Nginx和Django的读写权限边界变得模糊第二直接暴露图片URL等于告诉别人文件名规则拼URL就能拖走整库图片。用视图动态读取文件则可以在输出环节统一设置响应头、做登录校验和防盗链判断。5.2 最小流式接口content_type与Content-Disposition参数分析import os import mimetypes from django.http import StreamingHttpResponse, HttpResponse from django.shortcuts import get_object_or_404 from .models import Page def serve_comic_image(request, page_id): page get_object_or_404(Page, pkpage_id) path page.image.path if not os.path.exists(path): return HttpResponse(status404) content_type mimetypes.guess_type(path)[0] or application/octet-stream response StreamingHttpResponse( open(path, rb), content_typecontent_type, ) response[Content-Disposition] \ finline; filenamepage_{page.page_no}.jpg response[Cache-Control] private, max-age86400 return response有两个参数需要重点说明。第一是StreamingHttpResponse的data参数必须传可迭代对象open(path, rb)返回的文件句柄正好满足它不会把整个文件读进内存再吐给客户端而是边读边发对多页漫画阅读是必要的平滑性第二是Content-Disposition用inline而不是attachment告诉浏览器在页面内显示而不是触发下载。mimetypes.guess_type自动识别JPEG还是PNG比硬编码content_typeimage/jpeg更不容易出错。5.3 防盗链与登录态给图片访问加一道闸URL暴露后任何人都可以拼page_id直接拖图。个人站点防盗链不用做太复杂校验HTTP_REFERER域名即可若想收紧到仅登录用户可见再加一层login_required。from django.contrib.auth.decorators import login_required login_required def serve_comic_image(request, page_id): referer request.META.get(HTTP_REFERER, ) if referer and request.get_host() not in referer: return HttpResponse(status403) # ... 5.2 中的流式输出逻辑注意两个容易踩的坑其一浏览器隐私模式下部分产品会裁剪Referer校验过严会导致图片全部白屏所以Referer为空时放行其二登录用户请求图片时img标签会携带CookieDjango默认的SameSiteLax策略允许这类跨站子资源请求不需要额外处理CSRF token。提示login_required生效后阅读页模板里的img标签无需改变写法图片请求会自动携带会话Cookie。5.4 两个高概率踩坑点FileResponse与整卷读图写到这里顺便清理两个常见的坑。第一是FileResponse和StreamingHttpResponse的边界前者处理文件关闭和Range请求播放器拖进度条需要206响应时应换成FileResponse漫画阅读是逐张拉取单张图单张几百KBStreamingHttpResponse性能足够。第二是不要一次性渲染整卷的img标签几十张图并发请求会把开发服务器拖到假死前端配合IntersectionObserver或滚动监听滚动到页面底部再往img的src里填图片地址是漫画站的标配懒加载姿势。打开浏览器开发者工具的Network面板翻页观察图片逐张发出请求、状态码200、响应大小与磁盘文件基本一致这套基于Django的个人漫画管理网站从后台录入到前台阅读的链路就在本地跑通了。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。