DEV Community

Ajith
Ajith

Posted on

Bookstore Management

As part of my Python full-stack internship, I was tasked with building a real-world e-commerce application from scratch: a bookstore management system with a catalog, inventory tracking, a shopping cart, checkout with payments, order management, reviews, and a wishlist. Here's what I built, how it's put together, and a few honest lessons from getting it running on my own machine.

The Feature List

The brief covered pretty much everything you'd expect from a real bookstore:

Book catalog — categories, authors, genres, and search across title, ISBN, author name, and description
Inventory management — live stock counts, a "reserved quantity" that prevents overselling the last copy while someone's payment is processing, and low-stock alerts (both in the admin panel and as an email-able management command for cron jobs)
Shopping cart — session-based, so it works without forcing a login, with quantity limits tied to actual available stock
Checkout — shipping address, payment method selection, live order summary, free-shipping threshold
User authentication — registration, login/logout, password reset, and a profile page, all built on Django's own django.contrib.auth rather than reinventing it
Order management — order history, a status timeline (Pending → Processing → Shipped → Delivered), and cancellation that releases reserved/purchased stock back to inventory
Reviews & ratings — one review per user per book, 1–5 stars, with average ratings surfaced everywhere a book appears
Wishlist — add, remove, and one-click "move to cart"

On top of the storefront, I also built a full Django REST Framework API covering books, authors, categories, genres, and reviews, with a staff-only low_stock endpoint for inventory dashboards — because a real bookstore eventually needs a mobile app or a partner integration, and building the API alongside the website (instead of bolting it on later) turned out to be much less painful.

The Stack
Backend: Django 4.2 + Django REST Framework + django-filter
Database: SQLite for local development, MySQL 8.x as a one-line config swap for anything closer to production
Frontend: Django templates + Bootstrap 5 (no separate frontend framework — for a project like this, server-rendered HTML is simpler to reason about and ships faster)
Payments: a mock gateway I wrote myself, so the whole checkout flow is demoable without real API keys — cards ending in 0000 even simulate a decline, so the retry-payment path isn't just theoretical
The Part Nobody Warns You About: Environment Setup

Here's the honestly useful part of this post. The code was the easy bit. The thing that actually ate an afternoon was getting a working Python environment on Windows:

Python version mismatches. I initially had Python 3.14 installed — brand new, and neither Pillow nor mysqlclient had prebuilt Windows wheels for it yet. Pip tried to compile them from source, which then failed because I didn't have a C compiler or MySQL's header files configured. The fix was simply installing Python 3.12 alongside 3.14 and pointing my virtual environment at that instead (py -3.12 -m venv venv). Newer isn't always better when your dependencies haven't caught up yet.
MySQL friction. Getting mysqlclient to build on Windows requires MySQL's C headers to be discoverable, which is its own rabbit hole — and then there's actually remembering the root password you set months ago (or didn't set at all). For a project like this, I ended up defaulting the whole app to SQLite for local development, with MySQL support still fully wired in behind a single environment variable (DB_ENGINE=mysql) for whenever a real deployment needs it. Django's ORM abstracts the database engine completely, so nothing in the application code needs to change either way — it's purely a settings toggle.
PowerShell isn't Bash. Small thing, but if you're following a tutorial written for Mac/Linux, source venv/bin/activate will fail silently-ish on Windows. It's venv\Scripts\Activate.ps1 instead, and you may need to loosen PowerShell's execution policy first (Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser).

None of this is hard once you know it — but it's exactly the kind of thing that isn't in the Django docs and eats real time on a first project.

What I'd Tell Past Me
Default to SQLite during development. Reach for MySQL/Postgres only when you actually need to test against it — every extra piece of infrastructure is one more thing that can be broken on setup day.
Pin dependency versions, but not too tightly against your Python version. A hard pin like Pillow==10.4.0 will break the moment someone runs a newer Python than existed when that pin was written. A version range gives pip room to pick a build that actually has a wheel.
Build the inventory logic before the checkout logic. Reserving stock at order-creation time (rather than just at payment-success time) is what stops two customers from "buying" the last copy of a book simultaneously — and it's much easier to bolt onto checkout from the start than to retrofit later.
Write a management command for the boring stuff. The low-stock report (check_low_stock) is three lines of ORM filtering, but as a scheduled command it turns into a genuinely useful daily alert with almost no extra work.
Wrapping Up

This project ended up being a solid cross-section of what "full-stack" actually means in practice: data modeling (inventory reservations, snapshot order items so price history doesn't silently change), auth and permissions, a REST API, session-based state (the cart), and — maybe most realistically — the unglamorous work of making sure a stranger on a fresh machine can actually get the thing running.

If you're doing something similar for your own internship or portfolio, my one piece of advice: get the environment setup boring and reliable first. Everything else is just Django.

Top comments (0)