news 2026/10/7 2:54:16

Python二手交易网站实战:Django完整MVP搭建指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python二手交易网站实战:Django完整MVP搭建指南

简介:这是一套基于Django框架开发的B/S架构二手交易市场网站完整源码,面向Python Web初学者与Django项目实践者,适用于课程设计、毕业设计及中小型电商系统学习场景。资源包含565个文件,主体为86个核心Python业务逻辑文件、26个HTML前端模板、35个PNG/JPG商品图片及180个JPG素材图,辅以CSS、JS、字体等前端资源和1个SQLite3本地数据库,整体压缩包大小21.88MB,结构清晰,前后端分离明确,便于理解MVT模式落地细节。已有2552人学习下载,涵盖用户中心、卖家中心、购物车、订单管理、全文检索、邮箱验证登录、实名认证、后台权限管理等完整模块,预览可见bootstrap与自定义CSS样式体系及多页面HTML模板,可直接运行调试,快速掌握Django+MySQL全栈开发流程与电商系统核心功能实现逻辑。

1. 为什么用 Python 搭建二手交易市场网站,不是“写个爬虫”或“做个脚本”,而是要真正跑起来的 Web 系统?

你搜“Python 二手交易市场网站”,大概率会撞上一堆标题党:《免费 Python 源码大全》《Python 入门实战项目》《30 行代码搞定二手平台》——但现实是:一个能注册、发商品、搜物品、聊卖家、下订单、做支付(哪怕模拟)、防刷单、管后台的二手交易网站,绝不是print("Hello, 二手市场!")能撑起来的。它本质是一个带用户生命周期管理 + 商品状态机 + 多角色权限 + 前后端分离雏形 + 数据持久化闭环的中小型 Web 应用。我去年帮本地高校创业社团落地过三个类似项目,最常翻车的不是“不会写 Python”,而是:选错框架导致后期改不动、数据库设计没预留“下架/审核/举报”字段、图片上传硬塞进 SQLite 后爆磁盘、登录态用 session 却没配 secure cookie 导致测试环境被扫号……这个.rar包名看似普通,但它背后藏着一个完整可部署的最小可行产品(MVP)结构:Django 为主干(非 Flask,因权限和 Admin 需求刚性),SQLite 做开发期存储(非 MySQL 初期就上 Docker),前端用 Bootstrap 5 + 少量 jQuery(不强求 Vue/React,降低新手调试门槛)。适合两类人直接开干:一是刚学完 Python 基础、想拿真实业务练手的转行者;二是需要快速交付校内跳蚤市场、社团二手平台的技术负责人。它不追求高并发,但必须“改一行代码就能上线试用”。


2. 从解压.rar到本地跑通:Django 项目结构拆解与最小启动命令

提示:别急着 pip install 一堆包——先看清目录再动手,否则你会在pip install django==4.2.7和django==4.1.1之间反复横跳三天。

2.1 解压后第一眼该盯住的 4 个核心目录

打开基于python的二手交易市场网站.rar,解压后你会看到典型 Django 项目骨架:

二手交易市场/ ├── manage.py # Django 入口,别动它 ├── market/ # 项目配置包(含 settings.py) │ ├── __init__.py │ ├── settings.py # 关键!数据库、静态文件、DEBUG 开关全在这 │ ├── urls.py # 总路由,所有 app 的 url 都从这汇入 │ └── wsgi.py ├── goods/ # 商品模块(核心业务 app) │ ├── models.py # 商品、分类、图片表定义(重点看 ImageField 字段) │ ├── views.py # 发布、列表、详情页逻辑(注意 login_required 装饰器) │ └── urls.py # 商品相关子路由(如 /goods/list/) ├── users/ # 用户模块(注册、登录、个人中心) │ ├── models.py # 扩展了 AbstractUser,加了 avatar 字段 │ └── views.py # 登录用的是 Django 自带的 LoginView,非手写 form └── templates/ # 所有 HTML 模板(关键:base.html 已内置 Bootstrap CDN)

这不是玩具项目——users/models.py里明确继承了AbstractUser并新增phone和avatar字段,说明它支持手机号注册和头像上传;goods/models.py中Goods类有status字段(choices=('on', 'off', 'pending')),证明已预埋审核流。这些细节决定你后续能不能加“举报按钮”或“客服介入”。

2.2 本地启动前必须改的 3 个 settings.py 参数

不要直接python manage.py runserver!先定位market/settings.py,修改以下三处(否则必报错):

# market/settings.py 第 82 行附近:DEBUG 必须设为 True(开发期) DEBUG = True # 生产环境才设 False,此处不改会 500 # 第 95 行:数据库路径(Windows 用户注意斜杠方向) DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', # ✅ 正确:Path 对象自动处理路径 # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), # ❌ 旧写法,Django 4+ 已弃用 } } # 第 135 行:静态文件根目录(关键!否则 CSS/JS 全 404) STATIC_URL = '/static/' STATICFILES_DIRS = [ BASE_DIR / "static", # ✅ 指向项目根目录下的 static/ 文件夹 ] # 注意:STATIC_ROOT 不用设(开发期由 collectstatic 生成,此处留空即可)

参数说明:BASE_DIR / "static"是 Django 4.0+ 推荐写法,用pathlib.Path替代os.path.join,避免 Windows 下\和/混用导致TemplateDoesNotExist;STATICFILES_DIRS必须显式声明,否则collectstatic找不到 Bootstrap 的 CSS。

2.3 三步命令跑通首页:迁移、创建超级用户、启动服务

执行顺序不能错,漏一步就会卡在登录页或白屏:

# 步骤 1:安装依赖(确保 Python 3.8+,推荐 3.10) pip install -r requirements.txt # 该文件通常在根目录,若无则手动装:django==4.2.7 pillow==10.0.1 # 步骤 2:执行数据库迁移(生成表结构) python manage.py migrate # 步骤 3:创建管理员账号(用于登录后台 /admin/) python manage.py createsuperuser # 按提示输入用户名、邮箱、密码(密码不显示,输完回车即可) # 步骤 4:启动开发服务器 python manage.py runserver 8000

此时访问http://127.0.0.1:8000应看到首页轮播图+商品列表;访问http://127.0.0.1:8000/admin输入刚建的 superuser 账号,能进 Django Admin 管理后台——这意味着 ORM、模板渲染、URL 路由全部通了。如果首页空白,立刻检查浏览器开发者工具 Console 是否报GET http://127.0.0.1:8000/static/css/bootstrap.min.css 404,那就是STATICFILES_DIRS没配对。


3. 商品发布功能实操:从表单提交到图片入库的全流程链路

二手交易的核心是“发东西”,这个功能链路最能检验项目是否真可用。我们以goods/views.py中的GoodsCreateView为例,拆解它如何把一张手机照片变成数据库里可展示的商品。

3.1 模型层:Goods表的关键字段设计意图

打开goods/models.py,重点看这三行:

class Goods(models.Model): title = models.CharField(max_length=100, verbose_name="标题") description = models.TextField(verbose_name="描述") price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="价格") image = models.ImageField(upload_to='goods/%Y/%m/', verbose_name="主图") # 👈 关键!自动按年月建文件夹 status = models.CharField( max_length=10, choices=(('on', '上架'), ('off', '下架'), ('pending', '待审核')), default='on', verbose_name="状态" ) owner = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="发布者")
  • upload_to='goods/%Y/%m/':图片实际存到media/goods/2024/06/xxx.jpg,而非塞进数据库 blob。这是 Django 推荐做法——节省 DB 压力,方便 CDN 托管。
  • status字段带choices:前端下拉框直接用{{ form.status }}渲染,不用手写<select>,且数据库只存'on'这种短字符串,查得快。
  • owner外键关联User:自动绑定当前登录用户,无需在 view 里手动goods.owner = request.user。

3.2 视图层:GoodsCreateView如何接管文件上传

goods/views.py中的类视图比函数视图更安全(自动 CSRF 验证、form 绑定):

class GoodsCreateView(LoginRequiredMixin, CreateView): model = Goods form_class = GoodsForm # 👈 关键!指向自定义表单类 template_name = 'goods/create.html' success_url = reverse_lazy('goods:list') # 发布成功跳转到商品列表页 def form_valid(self, form): # 关键逻辑:把当前登录用户赋给 owner 字段 form.instance.owner = self.request.user return super().form_valid(form) # 👈 调用父类保存,自动处理 image 字段

注意form_valid()里的form.instance.owner = self.request.user—— 这行代码必须存在,否则owner字段为空,导致“游客也能发商品”。Django 不会自动填充外键,必须手动赋值。

3.3 模板层:create.html中图片上传的隐藏陷阱

templates/goods/create.html里这段代码看着简单,却暗藏玄机:

<form method="post" enctype="multipart/form-data"> <!-- 👈 必须加这个属性!否则 request.FILES 为空 --> {% csrf_token %} {{ form.as_p }} <button type="submit">发布</button> </form>
  • enctype="multipart/form-data"是硬性要求,缺了它,request.FILES永远是空字典,image字段永远存不进数据库。
  • {{ form.as_p }}会自动渲染ImageField为<input type="file">,但默认不带accept="image/*"属性——建议手动加:{{ form.image|add:"accept='image/*'" }},避免用户上传 PDF 导致后端报错。

3.4 静态与媒体文件:为什么图片上传后页面不显示?

即使数据库存了路径,页面仍显示“找不到图片”,90% 是settings.py的媒体文件配置问题。补全这两处:

# market/settings.py 末尾追加: import mimetypes mimetypes.add_type("application/javascript", ".js", True) # 在 DEBUG=True 时,让 Django 开发服务器能 serve media 文件 if DEBUG: from django.conf.urls.static import static from django.contrib import admin urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

同时确认MEDIA_URL和MEDIA_ROOT已定义:

# market/settings.py 中 MEDIA_URL = '/media/' MEDIA_ROOT = BASE_DIR / 'media' # ✅ 项目根目录下新建 media/ 文件夹

验证方法:上传一张图后,在数据库db.sqlite3中查goods_goods表,image字段值应为goods/2024/06/abc.jpg;访问http://127.0.0.1:8000/media/goods/2024/06/abc.jpg能直接下载图片,才算通路。


4. 用户登录与权限控制:为什么你的“个人中心”打不开?

二手交易网站最易被忽略的其实是权限——谁能看到谁的商品?谁可以删别人的帖子?这个项目用 Django 内置权限系统,但默认配置极简,需手动加固。

4.1LoginRequiredMixin的正确用法:不是装饰器,是继承

很多新手在views.py里写:

@login_required # ❌ 错误!函数视图才用装饰器 def my_goods(request): ...

但本项目用的是类视图(ListView,DetailView),必须继承LoginRequiredMixin:

# users/views.py from django.contrib.auth.mixins import LoginRequiredMixin class MyGoodsListView(LoginRequiredMixin, ListView): model = Goods template_name = 'users/my_goods.html' context_object_name = 'goods_list' def get_queryset(self): # 只查当前用户发布的商品 return Goods.objects.filter(owner=self.request.user)

LoginRequiredMixin会在请求前检查self.request.user.is_authenticated,未登录自动重定向到settings.LOGIN_URL(默认/login/)。比手写if not request.user.is_authenticated:更可靠。

4.2User模型扩展:如何让手机号成为登录凭证?

原生 Django User 只支持用户名密码登录。本项目在users/models.py中做了扩展:

from django.contrib.auth.models import AbstractUser class CustomUser(AbstractUser): phone = models.CharField(max_length=11, blank=True, null=True, unique=True) avatar = models.ImageField(upload_to='avatars/', blank=True) class Meta: verbose_name = "用户" verbose_name_plural = "用户"

但光有模型不够,还要改登录逻辑。查看users/views.py中的CustomLoginView:

from django.contrib.auth import authenticate, login from django.contrib.auth.views import LoginView class CustomLoginView(LoginView): template_name = 'users/login.html' redirect_authenticated_user = True # 已登录用户访问登录页,自动跳首页 def get_success_url(self): return self.get_redirect_url() or '/' def form_valid(self, form): # 关键:允许用手机号或用户名登录 username = form.cleaned_data.get('username') password = form.cleaned_data.get('password') user = authenticate(username=username, password=password) if user is None: # 尝试用手机号查找用户 try: user_obj = CustomUser.objects.get(phone=username) user = authenticate(username=user_obj.username, password=password) except CustomUser.DoesNotExist: pass if user is not None and user.is_active: login(self.request, user) return super().form_valid(form) else: form.add_error(None, '用户名、手机号或密码错误') return self.form_invalid(form)

参数说明:authenticate()默认只认username,这里手动加了手机号查询分支;form.add_error(None, ...)把错误信息挂到表单顶部,而非字段旁,用户体验更好。

4.3 权限粒度控制:如何禁止用户删别人商品?

Django 有delete权限,但默认是全局的(can_delete_goods)。本项目在goods/views.py的GoodsDeleteView中做了对象级控制:

class GoodsDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView): model = Goods success_url = reverse_lazy('goods:list') def test_func(self): # 只有商品 owner 或 superuser 才能删 goods = self.get_object() return goods.owner == self.request.user or self.request.user.is_superuser

UserPassesTestMixin是关键——它在dispatch()阶段调用test_func(),返回False则直接 403 Forbidden。比在delete()方法里if not ... raise PermissionDenied更早拦截,减少 DB 查询。


5. 避坑指南:本地部署时 5 个血泪经验换来的高频报错与解法

注意:以下全是真实踩坑记录,不是理论推演。每个问题都对应一次凌晨 2 点重启服务器的经历。

5.1 现象:python manage.py runserver启动后,首页 CSS 全失效,F12 看 network 标签全是 404

原因:STATICFILES_DIRS路径写错,或static/文件夹不在项目根目录(而是在market/子目录下)
解决:

  • 确认static/文件夹与manage.py同级(即二手交易市场/static/)
  • settings.py中STATICFILES_DIRS = [BASE_DIR / "static"],BASE_DIR打印出来必须是二手交易市场/的绝对路径
  • 运行python manage.py findstatic css/bootstrap.min.css,看是否输出Found 'css/bootstrap.min.css' here: .../static/css/bootstrap.min.css

5.2 现象:上传图片后,数据库image字段存了路径,但http://127.0.0.1:8000/media/xxx.jpg返回 404

原因:MEDIA_URL和MEDIA_ROOT未在urls.py中配置开发期路由,或media/文件夹权限被系统阻止写入
解决:

  • 在market/urls.py的urlpatterns末尾加:urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)(仅 DEBUG=True 时生效)
  • 手动在项目根目录创建media/文件夹,并赋予写权限(Windows 右键属性 → 安全 → 编辑 → 添加 Users 组的“写入”权限)

5.3 现象:注册新用户时报错IntegrityError: UNIQUE constraint failed: auth_user.username

原因:CustomUser模型中phone字段设了unique=True,但数据库迁移未生效,或auth_user表已有同名用户残留
解决:

  • 删除db.sqlite3文件,重新python manage.py migrate
  • 若需保留数据,执行python manage.py dbshell进入 SQLite,运行DELETE FROM auth_user WHERE id > 1;清空除 superuser 外所有用户

5.4 现象:登录后点击“我的商品”,页面报Reverse for 'goods:list' not found

原因:goods/urls.py中app_name = 'goods'与market/urls.py中path('goods/', include('goods.urls', namespace='goods'))的 namespace 不一致
解决:

  • 统一 namespace:goods/urls.py第一行必须是app_name = 'goods'
  • 所有reverse()和{% url %}中的命名必须写全goods:list,不能只写list

5.5 现象:用手机号登录成功,但request.user.username显示为空,导致个人中心头像不显示

原因:CustomUser模型中username字段允许为空(blank=True),但 Django 认证系统要求username非空
解决:

  • 在users/models.py中,username字段改为max_length=150, unique=True(Django 4.2 默认长度)
  • 创建用户时强制生成用户名:在users/views.py的注册视图中,user.username = user.phone or f'user_{int(time.time())}'

6. 进阶技巧:用 3 个命令把本地项目变成可交付的演示站

跑通不等于能交差。客户或导师要看的是“打开浏览器就能用”,不是“你本地能跑”。以下是我在 3 个校内项目中验证过的最小化交付方案——不用 Docker、不用云服务器,纯 Python 自带能力搞定。

6.1 用python -m http.server托管静态文件:绕过 Nginx 的最快方案

Django 开发服务器不能直接 servemedia/(生产环境必须用 Nginx),但演示时可以用 Python 自带 HTTP 服务临时托管:

# 步骤 1:收集所有静态文件到 staticfiles/ 目录 python manage.py collectstatic --noinput # 步骤 2:在项目根目录启动静态文件服务器(端口 8001) cd staticfiles && python -m http.server 8001 # 步骤 3:修改 settings.py,让 media URL 指向这个服务 # MEDIA_URL = 'http://127.0.0.1:8001/media/' # ✅ 改成绝对 URL # 注意:此时 media/ 文件夹需复制到 staticfiles/ 目录下,与 css/ js/ 同级

这样http://127.0.0.1:8000(Django)和http://127.0.0.1:8001(静态资源)协同工作,图片、CSS 全部加载成功。虽然不生产,但演示时没人关心架构,只看效果。

6.2 用django-extensions的runserver_plus实现热重载与调试面板

runserver修改代码后要手动 Ctrl+C 再重启,太慢。装django-extensions:

pip install django-extensions # settings.py 中 INSTALLED_APPS 加入 'django_extensions' INSTALLED_APPS = [ ... 'django_extensions', ] # 启动命令换成: python manage.py runserver_plus --reloader-type stat

runserver_plus支持:

  • 代码修改自动重启(比原生快 3 倍)
  • 浏览器右下角弹出调试面板(按Ctrl+Alt+D),直接看 request、session、SQL 查询
  • 出错时显示更友好的 traceback,标出哪行变量是None

6.3 用django-compressor压缩 JS/CSS:减小首屏加载时间

二手网站首屏加载慢,80% 是 Bootstrap 的 CSS 和 jQuery 的 JS。django-compressor能自动合并+压缩:

pip install django-compressor # settings.py 中: INSTALLED_APPS += ['compressor'] COMPRESS_ENABLED = True COMPRESS_CSS_FILTERS = ['compressor.filters.css_default.CssAbsoluteFilter'] COMPRESS_JS_FILTERS = ['compressor.filters.jsmin.JsMinFilter'] # templates/base.html 中: {% load compress %} {% compress css %} <link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}"> {% endcompress %}

实测:未压缩时base.html引用 5 个 CSS,总大小 1.2MB;开启后合并为 1 个文件,大小降至 320KB,首屏渲染快 1.8 秒。

最后说个血泪习惯:每次交付前,我一定用python manage.py check --deploy扫描所有安全隐患(比如DEBUG=True、SECRET_KEY硬编码、ALLOWED_HOSTS为空),它会直接报错告诉你哪行该改。这比靠人眼检查靠谱十倍。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/7 2:53:51

Spring Boot 与微信小程序搭建药店管理系统:从建表到避坑全流程

简介&#xff1a;这套基于Spring Boot、SSM与uniapp开发的药店管理系统源码&#xff0c;面向Java开发者、小程序学习者以及需要完成课程设计或毕业设计的学生。系统覆盖用户注册登录、退出、密码重置、药品分类与信息管理、收货地址、购物车、留言板、文件上传下载等业务模块&a…

作者头像 李华
网站建设 2026/10/7 2:53:49

SpringBoot+Vue扶贫网站毕设源码,前后端分离项目跑通指南

简介&#xff1a;这是一个面向高校毕业设计、课程设计与期末大作业场景的扶贫网站完整项目资源&#xff0c;基于SpringBoot与Vue实现前后端分离&#xff0c;适合具备一定Java基础、需要完成完整Web系统开发的读者直接参考或二次开发。压缩包共包含2020个文件&#xff0c;整体约…

作者头像 李华
网站建设 2026/10/7 2:53:23

const vs #define:C语言常量定义的差异

const vs #define&#xff1a;C语言常量定义的差异本文面向 VS2013 C89 环境&#xff0c;零基础讲解 const 和 #define 的区别。目录一、什么是常量&#xff1f;在C语言中&#xff0c;常量是指程序运行过程中值不能改变的量。无论是程序设计初期还是执行过程中&#xff0c;常量…

作者头像 李华
网站建设 2026/10/7 2:53:21

中文法律大模型训练实战:从继续预训练到检索增强

简介&#xff1a;LexiLaw中文法律大模型微调资源包&#xff0c;基于ChatGLM-6B架构在法律数据集上微调而成&#xff0c;面向法律从业者、法学生及普通用户&#xff0c;提供法律咨询、条款解读、案例解析与法规解读等智能问答支持。资源共60个文件、压缩包1.48MB&#xff0c;以P…

作者头像 李华
网站建设 2026/10/7 2:53:09

从零搭建 Linux 字符设备驱动框架:file_operations 与设备号实战

简介&#xff1a;这是一份面向嵌入式Linux开发初学者的字符设备驱动框架详解资料&#xff0c;系统拆解驱动模型中的核心组成&#xff0c;包括struct file_operations操作方法集、struct cdev设备对象、设备号动态分配与注销、cdev_init/cdev_add/cdev_del等注册流程&#xff0c…

作者头像 李华