Skip to content

Latest commit

 

History

10 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

The Coffee Shop

A small Django eCommerce site for a coffee shop, styled with Bootstrap 5 and a custom stylesheet layered on top. Visitors browse a catalogue of coffee gear and beans, fill a shopping cart without needing an account, and register or log in when they check out. Orders reduce stock, an invoice is emailed (to the terminal in development), and a "Contact us" form in the footer sends enquiries to the shop owner.

Home page screenshot

Tech stack

  • Python 3 + Django 6.0
  • Bootstrap 5.3.8 and Font Awesome, loaded from a CDN in base.html
  • Custom CSS in shop/static/style.css, linked after Bootstrap so its rules win
  • SQLite (db.sqlite3), Django's built-in file-based database - no separate database server, so setup is a single migrate step
  • Server-rendered Django templates (no separate front end)

Setup

Run these from the coffee_shop/ folder (the one containing manage.py):

# 1. Create and activate a virtual environment
python -m venv venv
venv\Scripts\activate           # Windows (PowerShell / cmd)
# source venv/bin/activate      # macOS / Linux

# 2. Install the dependencies
pip install -r ../requirements.txt

# 3. Create the database and load the starting stock
python manage.py migrate

# 4. Start the development server
python manage.py runserver

The site is then available at http://127.0.0.1:8000/.

requirements.txt lives in the folder above manage.py, which is why step 2 uses ../requirements.txt. It pins Django 6.0.7 and the three packages Django installs alongside itself (asgiref, sqlparse, tzdata), so everyone gets the same versions:

asgiref==3.12.1
Django==6.0.7
sqlparse==0.5.5
tzdata==2026.3

The twelve starting products are loaded by a data migration (shop/migrations/0004_seed_products.py), so the shop has stock as soon as migrate has run. Running it again will not create duplicates.

Configuration

No secret key or email address is stored in the repository. Everything configurable is read from the environment, with development-friendly defaults so the steps above work with nothing set:

Variable Default Purpose
DJANGO_SECRET_KEY a new random key each start-up Signs sessions and password-reset tokens. Must be set to a fixed value in production
DJANGO_DEBUG True Set to False in production
DJANGO_ALLOWED_HOSTS localhost,127.0.0.1 Comma-separated hostnames the site will answer to
CONTACT_EMAIL shop-owner@example.com Where the "Contact us" form sends enquiries

Because the development fallback generates a fresh secret key on every start, restarting the server signs out anyone who was logged in. Set DJANGO_SECRET_KEY if you want sessions to survive a restart.

Tests

The suite covers the areas where a mistake would be expensive: the cart's stock ceiling, the all-or-nothing stock check at checkout, the price captured on each order line, and the rule that a buyer can only open their own orders. Registration, login (including the check that a hand-crafted next cannot bounce a user off-site), the contact form and the password-reset flow are covered too.

python manage.py test shop
Ran 53 tests in 15.030s

OK

Using the site

Page URL Notes
Home / product grid / Open to everyone. "Buy" adds one item to the cart
Cart /cart/ Remove one, remove all, or continue to checkout
Register /register/buyer/ Creates the account and logs you straight in
Login /login/ Session expires after one day
Forgot password /password-reset/ Emails a one-time reset link (see below)
Checkout /checkout/ Requires an account - signed-out shoppers are sent to login and come back
Confirmation /confirmation/<order id>/ Shown after a successful order
Order detail /orders/<order id>/ A buyer can only see their own orders
Django admin /admin/ Manage products, orders and buyers

Browsing and the cart

The cart is stored in the session, so anyone can fill one without signing up, and it survives logging in. Quantities are capped at the stock actually on hand - asking for more than is available shows a warning rather than over-selling. Out-of-stock products show a disabled "Sold out" button.

Checking out

Checkout requires a logged-in user. The whole cart is checked for stock before anything is written, so one sold-out item cannot leave a half-filled order behind with earlier products' stock already deducted. The order and its line items are then created inside a single database transaction, stock is reduced, and the price of each item is stored on the order line (price_at_checkout), so later price changes don't rewrite order history.

Creating an admin account

The Django admin is used to manage products, orders and buyers. Create a superuser from the command line:

python manage.py createsuperuser

Then sign in at /admin/.

Email (order invoices, password resets, contact form)

Email is printed to the terminal running runserver, not delivered to a real inbox:

EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"

No mail server or credentials are needed. To reset a password:

  1. Go to /password-reset/ and enter the email address on the account.
  2. Switch to the terminal running the server and find the "Password Reset" message.
  3. Copy the link it contains (http://127.0.0.1:8000/reset/<uid>/<token>/), open it in the browser, and set a new password.

The same page is shown whether or not the email matched an account, so the form can't be used to find out which addresses are registered.

The "Contact us" form in the home page footer sends to CONTACT_EMAIL. That defaults to the placeholder shop-owner@example.com and can be overridden with an environment variable, so no real address is committed to the repository.

Bootstrap and custom CSS

Bootstrap is loaded from the CDN in shop/templates/base.html, with style.css linked after it so the custom rules take precedence where they overlap.

Bootstrap feature Where it is used
Grid (row, row-cols-*, col-md-*) Product cards, three to a row on medium screens and up, wrapping automatically for any number of products
Responsive navbar with collapse toggler base.html - links collapse to a hamburger menu on small screens
Horizontal form (col-form-label, form-control) "Contact us" form in the home page footer
Toasts Pop-up confirmations for "added to your cart", removals and contact-form results
Utility classes (d-flex, ms-auto, mt-4, fw-bold) Spacing and alignment throughout
img-fluid Product photos, overridden in style.css to a fixed height with object-fit: cover so the grid stays even

The custom stylesheet defines the coffee theme (browns, cream and gold) as CSS variables in :root and reuses them throughout, and adds the zoom-and-glow hover effect on product images.

Data model

Model Purpose
Product An item for sale: title, description, price, stock quantity and the filename of its photo. in_stock is True while quantity is above zero
Buyer A customer, linked one-to-one to Django's built-in User, with a saved delivery address
Order A buyer's order: shipping address, status and date. total adds up its line items
OrderItem One product line on an order, holding the quantity and the price at the time of purchase

Project layout

coffee_shop/
├── README.md                      # this file
├── .gitignore                     # keeps the database, venv and caches out of git
├── requirements.txt               # pinned Python dependencies
├── website.html                   # a standalone Bootstrap grid, kept as a reference
└── coffee_shop/
    ├── manage.py                  # Django command-line entry point
    ├── db.sqlite3                 # SQLite database - created locally by `migrate`
    ├── coffee_shop/               # project configuration
    │   ├── settings.py            # settings (database, static files, email backend)
    │   ├── urls.py                # root URL configuration
    │   └── wsgi.py / asgi.py      # server entry points
    └── shop/                      # the main application
        ├── models.py              # Product, Buyer, Order, OrderItem
        ├── views.py               # all page logic, auth and password reset
        ├── urls.py                # URL routes (namespaced under "shop")
        ├── forms.py               # buyer registration form
        ├── admin.py               # Django admin registrations
        ├── tests.py               # the test suite
        ├── migrations/            # schema migrations + the product seed data
        ├── templates/
        │   ├── base.html          # shared layout: Bootstrap, navbar, toasts
        │   └── shop/              # home, cart, checkout, confirmation, auth pages
        └── static/
            ├── style.css          # custom CSS layered over Bootstrap
            └── assets/            # product photographs

About

A small Django eCommerce site for a coffee shop, styled with Bootstrap 5.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages