ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

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

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模板可直接运行调试快速掌握DjangoMySQL全栈开发流程与电商系统核心功能实现逻辑。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 django4.2.7和django4.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 下\和/混用导致TemplateDoesNotExistSTATICFILES_DIRS必须显式声明否则collectstatic找不到 Bootstrap 的 CSS。2.3 三步命令跑通首页迁移、创建超级用户、启动服务执行顺序不能错漏一步就会卡在登录页或白屏# 步骤 1安装依赖确保 Python 3.8推荐 3.10 pip install -r requirements.txt # 该文件通常在根目录若无则手动装django4.2.7 pillow10.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_length100, verbose_name标题) description models.TextField(verbose_name描述) price models.DecimalField(max_digits10, decimal_places2, verbose_name价格) image models.ImageField(upload_togoods/%Y/%m/, verbose_name主图) # 关键自动按年月建文件夹 status models.CharField( max_length10, choices((on, 上架), (off, 下架), (pending, 待审核)), defaulton, verbose_name状态 ) owner models.ForeignKey(User, on_deletemodels.CASCADE, verbose_name发布者)upload_togoods/%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 methodpost enctypemultipart/form-data !-- 必须加这个属性否则 request.FILES 为空 -- {% csrf_token %} {{ form.as_p }} button typesubmit发布/button /formenctypemultipart/form-data是硬性要求缺了它request.FILES永远是空字典image字段永远存不进数据库。{{ form.as_p }}会自动渲染ImageField为input typefile但默认不带acceptimage/*属性——建议手动加{{ form.image|add:acceptimage/* }}避免用户上传 PDF 导致后端报错。3.4 静态与媒体文件为什么图片上传后页面不显示即使数据库存了路径页面仍显示“找不到图片”90% 是settings.py的媒体文件配置问题。补全这两处# market/settings.py 末尾追加 import mimetypes mimetypes.add_type(application/javascript, .js, True) # 在 DEBUGTrue 时让 Django 开发服务器能 serve media 文件 if DEBUG: from django.conf.urls.static import static from django.contrib import admin urlpatterns static(settings.MEDIA_URL, document_rootsettings.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(ownerself.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_length11, blankTrue, nullTrue, uniqueTrue) avatar models.ImageField(upload_toavatars/, blankTrue) class Meta: verbose_name 用户 verbose_name_plural 用户但光有模型不够还要改登录逻辑。查看users/views.py中的CustomLoginViewfrom 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(usernameusername, passwordpassword) if user is None: # 尝试用手机号查找用户 try: user_obj CustomUser.objects.get(phoneusername) user authenticate(usernameuser_obj.username, passwordpassword) 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_superuserUserPassesTestMixin是关键——它在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.css5.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_rootsettings.MEDIA_ROOT)仅 DEBUGTrue 时生效手动在项目根目录创建media/文件夹并赋予写权限Windows 右键属性 → 安全 → 编辑 → 添加 Users 组的“写入”权限5.3 现象注册新用户时报错IntegrityError: UNIQUE constraint failed: auth_user.username原因CustomUser模型中phone字段设了uniqueTrue但数据库迁移未生效或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, namespacegoods))的 namespace 不一致解决统一 namespacegoods/urls.py第一行必须是app_name goods所有reverse()和{% url %}中的命名必须写全goods:list不能只写list5.5 现象用手机号登录成功但request.user.username显示为空导致个人中心头像不显示原因CustomUser模型中username字段允许为空blankTrue但 Django 认证系统要求username非空解决在users/models.py中username字段改为max_length150, uniqueTrueDjango 4.2 默认长度创建用户时强制生成用户名在users/views.py的注册视图中user.username user.phone or fuser_{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:8000Django和http://127.0.0.1:8001静态资源协同工作图片、CSS 全部加载成功。虽然不生产但演示时没人关心架构只看效果。6.2 用django-extensions的runserver_plus实现热重载与调试面板runserver修改代码后要手动 CtrlC 再重启太慢。装django-extensionspip install django-extensions # settings.py 中 INSTALLED_APPS 加入 django_extensions INSTALLED_APPS [ ... django_extensions, ] # 启动命令换成 python manage.py runserver_plus --reloader-type statrunserver_plus支持代码修改自动重启比原生快 3 倍浏览器右下角弹出调试面板按CtrlAltD直接看 request、session、SQL 查询出错时显示更友好的 traceback标出哪行变量是None6.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 relstylesheet href{% static css/bootstrap.min.css %} {% endcompress %}实测未压缩时base.html引用 5 个 CSS总大小 1.2MB开启后合并为 1 个文件大小降至 320KB首屏渲染快 1.8 秒。最后说个血泪习惯每次交付前我一定用python manage.py check --deploy扫描所有安全隐患比如DEBUGTrue、SECRET_KEY硬编码、ALLOWED_HOSTS为空它会直接报错告诉你哪行该改。这比靠人眼检查靠谱十倍。希望帮到你。本文还有配套的精品资源点击获取
返回列表