Django splits a codebase into two different-sized units. The project is the container for the whole site: settings, the top-level URL table, the list of which pieces are switched on. An app is a smaller, focused slice living inside it — a chunk of models, views, and templates built around one job:
toolshed/
├── manage.py
├── toolshed/ # the project package — settings, root URLs
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py / asgi.py
├── catalog/ # an app — tools, categories, tags
│ ├── models.py
│ ├── views.py
│ ├── urls.py
│ ├── admin.py
│ └── migrations/
└── loans/ # a second app — the borrowing workflow
├── models.py
├── views.py
└── migrations/
Priya's weekend version put everything — tools, loans, the handful of view functions ToolShed needed — into a single app named core. Nothing wrong with that for a weekend project nobody else was going to touch. The split into catalog (what a tool is) and loans (who currently has it) happened later, once a bug fix meant scrolling past unrelated code to find the right function. The deeper reason for the split isn't tidiness, though — it's that loans importing straight from catalog's internals, rather than treating it as a black box with a public surface, is the kind of dependency that makes either app harder to change on its own later. And an app only counts if settings.py's INSTALLED_APPS list actually names it — a folder full of models and views sitting on disk, unlisted there, is invisible to migrations, the admin, and everything else Django does at startup.