Build a Django inventory system with AI, and catch its mistakes

An inventory management system for an office IT store, built in Python and Django with an AI coding assistant: stock in and out across three locations, reorder alerts and a dashboard. Below are the rules that made it trustworthy, the code that matters, the four mistakes the AI made, and a checklist for reviewing AI-written code.

Try it: live demo (sample data, resets every night).

1. Give the AI rules, not screens

“Build me an inventory app” gets you an inventory-shaped app. These four rules got a correct one:

  1. Stock is never typed in. It is always the sum of every movement in and out.
  2. Never issue more than is on the shelf at that location (not just in total).
  3. Every movement has a reference: a purchase order, issue slip or help desk ticket.
  4. Write a test for each rule.

2. The data model

  • Category, Supplier, Location: simple lists.
  • Item: SKU, name, unit cost, reorder level.
  • StockMovement: item, location, type (in, out, adjustment), signed quantity, reference, who and when.

There is no stock column. Current stock is calculated:

class ItemQuerySet(models.QuerySet):
    def with_stock(self):
        stock = Coalesce(Sum("movements__quantity"), Value(0))
        return self.annotate(stock=stock).annotate(
            value=ExpressionWrapper(
                F("stock") * F("unit_cost"),
                output_field=DecimalField(max_digits=14, decimal_places=2),
            )
        )

    def low_stock(self):
        return self.with_stock().filter(is_active=True, stock__lte=F("reorder_level"))

3. The rule that protects stock

This lives in the model’s clean(), so every form and the admin get the same check:

def clean(self):
    self.normalise()  # stock in = +, stock out = -
    if not self.quantity:
        raise ValidationError({"quantity": "Quantity cannot be zero."})
    if self.quantity < 0 and self.item_id and self.location_id:
        available = self.item.stock_at(self.location)
        if available + self.quantity < 0:
            raise ValidationError({"quantity": (
                f"Only {available} {self.item.get_unit_display()} "
                f"in stock at {self.location}.")})

4. The four mistakes the AI made

  1. Prices wrapped onto two lines on phones. Nothing was wrong in the code, so no test failed; it only showed up in phone screenshots. Fix: white-space: nowrap on number columns.
  2. Chart data encoded as JSON twice (once in the view, again by json_script) and decoded twice in the browser. It worked, but was fragile. Fix: pass a plain dict to json_script.
  3. Restocks counted before they arrived in the sample data, leaving nine of twenty items low or empty. Fix: hold each purchase order until its arrival date.
  4. Issuing stock made it go up. The sample data used bulk_create(), which never calls save(), so stock-out rows kept their positive quantity. Nothing crashed. Fix: set the sign on each row before the bulk insert, and a test that fails if any item is ever negative at any location.
m = StockMovement(item=item, location=loc, kind=kind, quantity=qty, reference=ref)
m.normalise()  # bulk_create skips save(), so sign it here
movements.append(m)
...
StockMovement.objects.bulk_create(movements)

5. Run it

pip install "Django>=5.2,<5.3"
python manage.py migrate
python manage.py seed_demo
python manage.py test inventory
python manage.py runserver

6. Put it online for free

The demo runs on PythonAnywhere’s free plan and is deployed by GitHub Actions: a push runs the tests, then a small script uploads the code and a fresh sample database through PythonAnywhere’s API (the token lives in GitHub secrets) and reloads the site. The same workflow reloads fresh sample data every night.

  • Demo mode: admin pages switched off, quantities capped, number of new records limited, debug off, secure cookies, secret key outside the code, and a banner saying the data resets nightly.
  • The catch: a free PythonAnywhere site must be renewed every month (one click on the Web tab). If you forget, it is switched off, not deleted.
  • Link to a short address on your own site (here, howitwork.net/demo/inventory/) so the demo can move hosts without breaking old links.

7. Checklist before you trust AI code

  • Give the business rules, and ask for a test for each one.
  • Search for shortcuts that skip your rules: bulk_create(), QuerySet.update(), raw SQL.
  • Check the numbers against something you know. If half the items are at zero, something is wrong.
  • Look at it on a real phone.

More IT guides · howITwork on YouTube