
简介本资源是一套基于Django框架开发的完整新闻网站及后台管理系统源码面向Python Web初学者与Django进阶学习者解决从零构建内容型Web应用的核心实践问题。项目采用标准MTV架构涵盖新闻发布、分类管理、标签系统、用户权限控制及Admin后台定制等典型业务场景适合用于课程设计、毕业项目或企业级内容平台原型开发。压缩包共2000个文件主体为85个Python后端逻辑文件、52个HTML模板、339个JS交互脚本、142个CSS/LESS样式文件及771张PNG图标资源辅以AdminLTE等成熟前端UI组件整体大小13.62MB。已有742人下载学习代码结构清晰、注释规范包含可直接运行的数据库迁移脚本、静态资源配置及supervisor进程管理示例便于快速部署与二次开发。1. 项目概述一个Django全栈新闻站点的诞生最近在整理硬盘翻出来一个几年前做的项目一个基于Django开发的新闻网站附带一个功能还算齐全的后台管理系统。当时是为了给本地一家小报社做线上转型的Demo虽然最后项目没上线但整个技术栈和实现思路我觉得挺有代表性的尤其是对于想从零开始理解一个完整Web应用如何运作的朋友来说。今天就把这个源码包拆开结合我当时的思考和实践聊聊怎么用Django从零搭建一个新闻站点以及后台管理那些“门道”。这个项目本质上是一个内容管理系统CMS核心就两件事前台给用户看新闻后台让编辑人员高效地管理这些新闻。听起来简单但里面涉及到用户认证、文章CRUD、图片处理、前端模板渲染、后台权限控制等一系列环节。Django作为Python领域最“重”的Web框架以其“开箱即用”的特性非常适合这类需要快速构建、结构清晰的中小型项目。国内Python Web开发Django的占有率一直很高尤其在需要自带后台、强调安全性和开发速度的企业级应用、内容发布平台里它几乎是首选。这个项目源码就是一个典型的Django全栈实践。2. 技术栈选型与项目结构解析拿到一个源码包第一步不是急着运行而是先看它的“骨架”。这个项目的技术栈非常经典是早期大约Django 1.11到2.0时代的标配组合。2.1 后端核心Django 数据库后端毫无悬念地选择了Django。我当时选型的主要考虑是第一项目需求明确就是新闻的增删改查和用户管理Django自带的Admin后台和ORM能省掉大量重复代码第二Django的文档极其完善社区活跃遇到任何问题几乎都能找到解决方案第三其内置的用户认证系统、表单处理、中间件等组件对于构建一个安全、稳定的后台管理系统至关重要。虽然现在看有些设计可能不如新兴的FastAPI灵活但对于需要快速交付、功能全面的CMS类项目Django的“全家桶”模式依然高效。数据库方面源码里默认配置的是SQLite。这是Django开发初期的默认选择好处是零配置文件即数据库非常适合本地开发和演示。但在实际生产环境中我强烈建议换成PostgreSQL或MySQL。以PostgreSQL为例它对JSON字段、全文搜索的支持更好更适合新闻内容这种可能包含富文本和复杂查询的场景。在settings.py里改几行配置就能切换# settings.py 生产环境配置示例 DATABASES { default: { ENGINE: django.db.backends.postgresql, NAME: mydatabase, USER: mydatabaseuser, PASSWORD: mypassword, HOST: localhost, PORT: 5432, } }2.2 前端呈现Django模板引擎这个项目的前端没有采用前后端分离架构比如Vue3DRF而是使用了Django自带的模板引擎。这在当时是主流做法现在对于内容导向、SEO重要的新闻站来说服务端渲染SSR依然有优势页面加载快对搜索引擎友好。模板主要放在templates目录下。通常会有几个核心文件base.html: 所有页面的基础模板定义了head、导航栏、页脚等通用部分。index.html: 首页模板负责展示新闻列表。detail.html: 新闻详情页模板。后台管理的模板通常继承自Django Admin的模板或者放在templates/admin目录下进行定制。前端样式使用了Bootstrap 3。这是一个非常务实的选择能快速搭建出风格统一、响应式的界面把开发重心放在业务逻辑上。源码中的静态文件CSS, JavaScript, 图片都放在static目录下。2.3 项目目录结构深潜解压源码.zip你会看到一个标准的Django项目结构。理解这个结构是读懂任何Django项目的基础news_site/ # 项目根目录 ├── manage.py # Django命令行工具入口 ├── news_site/ # 项目配置目录与项目同名 │ ├── __init__.py │ ├── settings.py # 项目所有设置重中之重 │ ├── urls.py # 项目级别的URL路由 │ ├── wsgi.py # WSGI服务器部署入口 │ └── asgi.py # ASGI服务器部署入口后期版本增加 ├── news/ # 一个应用app负责核心新闻业务 │ ├── migrations/ # 数据库迁移文件由Django自动生成 │ ├── __init__.py │ ├── admin.py # 注册模型到Django Admin后台 │ ├── apps.py # 应用配置 │ ├── models.py # 数据模型定义核心中的核心 │ ├── tests.py # 单元测试 │ ├── urls.py # 应用级别的URL路由可选 │ └── views.py # 视图函数处理业务逻辑 ├── templates/ # 全局模板目录 ├── static/ # 全局静态文件目录 └── media/ # 用户上传的文件目录如图片这个结构清晰地将配置、应用、静态资源分离。一个关键经验是尽量保持每个app的功能单一。比如newsapp只处理新闻相关如果需要用户评论功能最好创建一个新的commentsapp。这样代码更易维护和复用。3. 核心数据模型设计与后台管理定制Django奉行“模型是真理之源”的理念。所有功能都始于models.py中的定义。这个新闻网站的核心模型通常包括Category新闻分类、Article新闻文章和Tag标签。3.1 模型定义的艺术打开news/models.py你会看到类似这样的代码from django.db import models from django.contrib.auth.models import User class Category(models.Model): 新闻分类 name models.CharField(分类名称, max_length100) slug models.SlugField(URL标识, uniqueTrue) # 用于生成友好的URL created_time models.DateTimeField(创建时间, auto_now_addTrue) class Meta: verbose_name 新闻分类 verbose_name_plural verbose_name # 在Admin中显示为复数形式 def __str__(self): return self.name class Tag(models.Model): 文章标签 name models.CharField(标签名, max_length100) slug models.SlugField(URL标识, uniqueTrue) def __str__(self): return self.name class Article(models.Model): 新闻文章 STATUS_CHOICES ( (draft, 草稿), (published, 已发布), ) title models.CharField(标题, max_length200) slug models.SlugField(URL标识, max_length200, unique_for_datepublish_time) author models.ForeignKey(User, on_deletemodels.CASCADE, verbose_name作者) category models.ForeignKey(Category, on_deletemodels.CASCADE, verbose_name分类) tags models.ManyToManyField(Tag, blankTrue, verbose_name标签) summary models.TextField(摘要, max_length500, help_text可选如为空则自动截取正文前N个字符) content models.TextField(正文) # 使用ImageField需要安装Pillow库 cover_image models.ImageField(封面图, upload_tonews/covers/%Y/%m/%d/, blankTrue) publish_time models.DateTimeField(发布时间, defaulttimezone.now) created_time models.DateTimeField(创建时间, auto_now_addTrue) updated_time models.DateTimeField(更新时间, auto_nowTrue) status models.CharField(状态, max_length10, choicesSTATUS_CHOICES, defaultdraft) views models.PositiveIntegerField(浏览量, default0, editableFalse) # 不可在后台直接编辑 class Meta: ordering [-publish_time] # 默认按发布时间倒序排列 verbose_name 新闻文章 verbose_name_plural verbose_name def __str__(self): return self.title def increase_views(self): 浏览量自增方法 self.views 1 self.save(update_fields[views])这里有几个设计要点和踩坑经验slug字段用于生成SEO友好的URL如/news/2023/10/20/my-article-title/比使用ID/news/123/好得多。unique_for_date参数确保同一天发布的文章slug不重复。ImageField依赖Pillow库处理图片。upload_to参数定义了图片在media目录下的存储路径按年月日分类便于管理。务必在服务器上配置好媒体文件的访问权限否则图片无法显示。时间字段auto_now_add只在创建时设置时间auto_now在每次保存时更新。defaulttimezone.now注意是调用函数timezone.now而不是timezone.now()。状态机使用choices参数定义文章状态草稿/已发布这是管理内容生命周期最简单有效的方式。editableFalse像views浏览量这种应该由程序逻辑更新的字段设为不可在后台编辑防止误操作。定义好模型后运行python manage.py makemigrations和python manage.py migrate命令Django就会自动在数据库中创建对应的表。3.2 激活并定制Django Admin后台Django Admin的强大之处在于几乎不用写前端代码就能获得一个功能强大的后台。在news/admin.py中注册模型from django.contrib import admin from .models import Article, Category, Tag admin.register(Article) class ArticleAdmin(admin.ModelAdmin): # 列表页显示字段 list_display (title, category, author, publish_time, status, views) # 列表页过滤器 list_filter (status, category, publish_time, author) # 搜索框可搜索的字段 search_fields (title, content, summary) # 详情页字段分组 fieldsets ( (基础信息, { fields: (title, slug, author, category, tags) }), (内容, { fields: (summary, content, cover_image) }), (发布设置, { fields: (publish_time, status) }), ) # 预填充slug字段通常根据title生成 prepopulated_fields {slug: (title,)} # 在编辑页显示“保存并继续编辑”等按钮 save_on_top True admin.register(Category) class CategoryAdmin(admin.ModelAdmin): list_display (name, slug, created_time) prepopulated_fields {slug: (name,)} admin.register(Tag) class TagAdmin(admin.ModelAdmin): list_display (name, slug) prepopulated_fields {slug: (name,)}这样访问/admin/用python manage.py createsuperuser创建的超管账号登录就能看到功能完善的后台了。你可以对文章进行增删改查、筛选、搜索。一个重要的经验对于内容量大的站点一定要用好list_filter和search_fields这是编辑人员效率的关键。另外可以为author字段设置默认值或者根据登录用户自动填充减少操作步骤。4. 前台功能实现从URL到模板的完整链路后台是给管理员用的前台才是给用户看的。Django的MTVModel-Template-View模式在这里清晰体现。4.1 视图View逻辑编写视图是连接模型和模板的桥梁负责处理业务逻辑。在news/views.py中我们通常需要以下几个视图from django.shortcuts import render, get_object_or_404 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from .models import Article, Category, Tag def article_list(request): 新闻首页/列表页 # 获取所有已发布的文章 articles_list Article.objects.filter(statuspublished).order_by(-publish_time) # 分页处理每页10条 paginator Paginator(articles_list, 10) page request.GET.get(page) try: articles paginator.page(page) except PageNotAnInteger: # 如果page参数不是整数显示第一页 articles paginator.page(1) except EmptyPage: # 如果页码超出范围显示最后一页 articles paginator.page(paginator.num_pages) return render(request, news/article_list.html, {articles: articles}) def article_detail(request, year, month, day, slug): 新闻详情页 # 根据URL中的年月日和slug精确获取文章 article get_object_or_404( Article, slugslug, publish_time__yearyear, publish_time__monthmonth, publish_time__dayday, statuspublished ) # 每次访问浏览量1 article.increase_views() # 获取相关文章例如同分类下的其他文章 related_articles Article.objects.filter( categoryarticle.category, statuspublished ).exclude(idarticle.id)[:5] # 排除自己取5篇 return render(request, news/article_detail.html, { article: article, related_articles: related_articles, }) def category_articles(request, slug): 分类文章列表页 category get_object_or_404(Category, slugslug) articles_list Article.objects.filter(categorycategory, statuspublished).order_by(-publish_time) # 同样需要分页... return render(request, news/category.html, {category: category, articles: articles_list})关键点get_object_or_404非常实用的快捷方式如果对象不存在直接返回404页面避免程序抛出异常。分页对于新闻列表分页是必须的。Django的Paginator类很好用但要注意处理各种边界情况非整数页码、超出范围等。increase_views浏览量更新放在视图里而不是模板中确保逻辑正确。这里用update_fields只更新views字段提高效率。4.2 URL路由配置视图写好了需要告诉Django哪个URL对应哪个视图。在项目根目录的urls.py中我们引入应用的URL配置# news_site/urls.py from django.contrib import admin from django.urls import path, include from django.conf import settings from django.conf.urls.static import static urlpatterns [ path(admin/, admin.site.urls), path(, include(news.urls)), # 将news应用的urls包含进来 ] # 开发环境下提供媒体文件的访问服务 if settings.DEBUG: urlpatterns static(settings.MEDIA_URL, document_rootsettings.MEDIA_ROOT)然后在news应用中创建自己的urls.py# news/urls.py from django.urls import path from . import views urlpatterns [ path(, views.article_list, namearticle_list), # 首页 path(article/int:year/int:month/int:day/slug:slug/, views.article_detail, namearticle_detail), # 详情页匹配友好URL path(category/slug:slug/, views.category_articles, namecategory_articles), # 分类页 ]这里的URL模式article/int:year/int:month/int:day/slug:slug/正好对应了视图article_detail的参数也和我们模型中slug字段的unique_for_date约束相匹配形成了清晰的、对SEO友好的URL结构。4.3 模板Template渲染与数据展示最后在templates/news/目录下创建模板文件。以article_list.html为例{% extends base.html %} {% block title %}新闻首页{% endblock %} {% block content %} div classcontainer h1 classmy-4最新新闻/h1 div classrow {% for article in articles %} div classcol-md-6 mb-4 div classcard {% if article.cover_image %} img src{{ article.cover_image.url }} classcard-img-top alt{{ article.title }} {% endif %} div classcard-body h5 classcard-title a href{% url article_detail article.publish_time.year article.publish_time.month article.publish_time.day article.slug %} {{ article.title }} /a /h5 p classcard-text text-muted small 发布于 {{ article.publish_time|date:Y-m-d H:i }} | 分类: a href{% url category_articles article.category.slug %}{{ article.category.name }}/a | 浏览: {{ article.views }} /small /p p classcard-text{{ article.summary|truncatechars:150 }}/p /div /div /div {% empty %} div classcol-12 p classtext-center暂无新闻。/p /div {% endfor %} /div !-- 分页导航 -- nav aria-labelPage navigation ul classpagination justify-content-center {% if articles.has_previous %} li classpage-item a classpage-link href?page{{ articles.previous_page_number }}上一页/a /li {% endif %} {% for num in articles.paginator.page_range %} {% if articles.number num %} li classpage-item activespan classpage-link{{ num }}/span/li {% else %} li classpage-itema classpage-link href?page{{ num }}{{ num }}/a/li {% endif %} {% endfor %} {% if articles.has_next %} li classpage-item a classpage-link href?page{{ articles.next_page_number }}下一页/a /li {% endif %} /ul /nav /div {% endblock %}模板中使用了Django模板语言DTL{% extends %}继承基础模板保持站点风格统一。{% for %}循环遍历文章列表。{% url %}模板标签用于生成URL避免硬编码。这是最佳实践当URL模式改变时所有链接自动更新。{{ variable|filter }}使用过滤器格式化数据如|date格式化时间|truncatechars截断文本。分页逻辑通过视图传入的articles对象是一个Page对象的属性如has_previous,paginator.page_range来实现。5. 项目部署与生产环境优化要点本地开发跑通了但要上线到公网还有一大堆坑要踩。这个源码包只是一个起点离真正的生产级应用还有距离。5.1 关键配置迁移首先必须修改settings.py中的关键配置绝不能把开发配置直接用于生产# settings.py 生产环境关键配置 DEBUG False # 必须关闭否则会暴露敏感信息 ALLOWED_HOSTS [yourdomain.com, www.yourdomain.com, 服务器IP地址] # 允许访问的域名/IP # 安全密钥务必从环境变量读取不要硬编码在代码中 SECRET_KEY os.environ.get(DJANGO_SECRET_KEY) # 数据库配置如前所述换用PostgreSQL/MySQL # ... # 静态文件和媒体文件配置 STATIC_URL /static/ STATIC_ROOT os.path.join(BASE_DIR, staticfiles) # 收集静态文件的目标目录 MEDIA_URL /media/ MEDIA_ROOT os.path.join(BASE_DIR, media) # 日志配置非常重要 LOGGING { version: 1, disable_existing_loggers: False, handlers: { file: { level: ERROR, class: logging.FileHandler, filename: os.path.join(BASE_DIR, logs/django_error.log), }, }, loggers: { django: { handlers: [file], level: ERROR, propagate: True, }, }, }5.2 使用Gunicorn和Nginx部署Django自带的开发服务器runserver性能很差且不安全绝不能用于生产。标准的部署方式是应用服务器使用Gunicorn或uWSGI来运行Django应用。pip install gunicorn gunicorn --workers 3 news_site.wsgi:application--workers参数根据服务器CPU核心数设置通常为2 * CPU核心数 1。反向代理服务器使用Nginx或Apache作为前端。Nginx负责处理静态文件效率远高于Django、负载均衡、SSL加密等并将动态请求转发给Gunicorn。# Nginx配置片段示例 (在 /etc/nginx/sites-available/your_site 中) server { listen 80; server_name yourdomain.com www.yourdomain.com; location /static/ { alias /path/to/your/project/staticfiles/; # 指向STATIC_ROOT expires 30d; } location /media/ { alias /path/to/your/project/media/; # 指向MEDIA_ROOT expires 30d; } location / { proxy_pass http://127.0.0.1:8000; # 转发给Gunicorn proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }配置好后运行python manage.py collectstatic收集所有静态文件到STATIC_ROOT目录然后重启Nginx。5.3 性能与安全加固数据库连接池Django默认每个请求新建数据库连接高并发下是瓶颈。可以使用django-db-connections或pgbouncer针对PostgreSQL来管理连接池。缓存新闻首页、分类页等不常变的内容非常适合缓存。Django提供了多种缓存后端内存、文件、数据库、Redis。使用Redis是最佳实践CACHES { default: { BACKEND: django_redis.cache.RedisCache, LOCATION: redis://127.0.0.1:6379/1, OPTIONS: { CLIENT_CLASS: django_redis.client.DefaultClient, } } }然后在视图中使用cache_page装饰器或模板片段缓存。安全头使用django-csp、django-cors-headers等中间件增加安全HTTP头防止XSS、点击劫持等攻击。防范常见攻击SQL注入Django ORM已基本免疫但绝对要避免使用原生SQL拼接。XSS模板系统默认转义变量{{ variable }}但如果你用|safe过滤器或mark_safe函数一定要确保内容绝对可信。CSRFDjango默认启用CSRF保护表单中务必包含{% csrf_token %}。文件上传限制上传文件的类型、大小并对图片进行重命名避免覆盖和恶意文件名。可以使用Pillow验证上传的是否为有效图片。6. 从源码到产品可扩展性与进阶思考这个源码提供了一个坚实的起点但一个真正的新闻产品还需要更多功能。这里分享几个我当时规划或后续补充的方向也是你拿到源码后可以深挖的点。6.1 功能扩展建议用户系统与评论集成Django内置的django.contrib.auth实现用户注册、登录、个人中心。评论功能可以单独建一个commentsapp使用GenericForeignKey关联到Article模型实现多态关联。全文搜索当新闻量上去后简单的标题搜索不够用。可以集成django-haystackWhoosh轻量或Elasticsearch强大实现全文检索、高亮、分词。RESTful API如果未来需要开发移动端App或与第三方系统对接可以使用Django REST Framework (DRF)快速构建API。这需要将项目改造成前后端分离架构。异步任务一些耗时的操作比如发送注册邮件、生成文章缩略图、处理视频转码应该放入异步队列如CeleryRedis避免阻塞HTTP请求。富文本编辑器Django Admin自带的文本框很简陋。可以集成django-ckeditor或django-tinymce让编辑人员能方便地排版、插入图片。6.2 代码质量与维护测试源码中通常缺少测试。务必为模型、视图、表单编写单元测试和集成测试。使用Django的TestCase这能极大减少上线后的问题。代码结构优化随着功能增加views.py和models.py会变得臃肿。可以考虑使用基于类的视图CBV来复用代码或者将业务逻辑抽离到单独的services.py或utils.py文件中。配置管理将开发、测试、生产环境的配置分离。使用python-decouple或django-environ库从环境变量读取敏感配置如SECRET_KEY,DATABASE_URL避免配置泄露。6.3 关于“企业级后台管理系统”的思考现在很多新的全栈项目喜欢用Vue3/React Element Plus/Ant Design Pro做后台前后端完全分离。这和Django Admin是两种思路Django Admin优势是快。对于标准化的增删改查需求几乎零前端开发专注业务模型。适合内部运营后台、快速原型。缺点是界面风格固定定制复杂的前端交互比较麻烦。前后端分离后台优势是体验好、定制强。可以做出非常复杂、交互丰富的单页面应用SPA用户体验更接近桌面软件。适合对后台操作体验要求高、需要复杂数据可视化、多步骤流程的项目。选择哪种取决于项目阶段和团队资源。初期用Django Admin快速搭建验证业务后期如果后台交互变得极其复杂再考虑用Vue3等重写前端Django后端提供API是完全可行的演进路径。最后运行这个源码很简单解压进入目录pip install -r requirements.txt安装依赖如果没有就手动安装Django, Pillow等python manage.py migrate创建数据库python manage.py createsuperuser创建管理员python manage.py runserver启动开发服务器。但更重要的是理解其背后的设计逻辑和每一行代码的意图这样才能把它变成你自己的东西并根据实际需求去改造和扩展。本文还有配套的精品资源点击获取