Django · Episode 3
Django in Production: Security, Templates, Types, and the Discipline Behind Reliable Apps
A practical Django podcast episode about building production-ready web apps nowadays: CSP, template partials, type hints, AI-assisted development, PostgreSQL, admin workflows, security habits, and why mature Django teams win through discipline rather than hype.
HostValerii S.Lead Full-Stack Engineer - React, Node and AI Platforms
GuestArjun Mehta — Principal Backend Engineer — LedgerWorks Studio
#3: Django in Production: Security, Templates, Types, and the Discipline Behind Reliable Apps
Original editorial from Softaims, published in a podcast-style layout—details, show notes, timestamps, and transcript—so the guidance is easy to scan and reference. The host is a developer from our verified network with experience in this stack; the full text is reviewed and edited for accuracy and clarity before it goes live.
Details
This episode focuses on production Django rather than beginner Django or framework hype.
The conversation explains why Django 6.0 features like built-in CSP support, template partials, and Tasks matter for real teams.
The guest discusses AI-assisted Django development honestly: useful for boilerplate and explanation, risky when developers stop reading the framework docs.
The episode covers type hints, PostgreSQL, admin workflows, security headers, migrations, testing, and operational habits.
The core message is that Django is powerful when teams treat it as a production system, not just a fast way to generate pages.
Show notes
- Django 6.0 built-in Content Security Policy tools
- Template partials and cleaner server-rendered interfaces
- Why Django Tasks standardize background work but do not remove the need for workers
- Type hints in Django projects
- AI tools for Django: helpful assistant, dangerous authority
- PostgreSQL as the default serious Django database choice
- Security headers, permissions, CSRF, authentication, and audit trails
- Admin customization as internal product design
- Testing migrations and permission boundaries
- How to review AI-generated Django code
- When to choose Django templates, APIs, or a separate frontend
- Advice for teams taking Django to production
Timestamps
- 0:00 — Cold open: production Django is not tutorial Django
- 2:30 — What separates a real Django app from a demo
- 5:00 — Django 6.0 and the security conversation
- 8:00 — Content Security Policy in practical terms
- 11:00 — Template partials and server-rendered interfaces
- 14:00 — Why teams are reconsidering heavy frontends
- 17:00 — Type hints in Django without turning it into Java
- 20:00 — AI-assisted Django development
- 23:00 — How to review AI-generated code
- 26:00 — PostgreSQL and data modeling discipline
- 29:00 — Admin workflows as internal products
- 32:00 — Permissions, audit logs, and operational trust
- 35:00 — Tasks, queues, and background work
- 38:00 — Testing what usually breaks
- 41:00 — Migrations as production events
- 44:00 — Choosing templates, APIs, or a separate frontend
- 47:00 — The production Django checklist
- 50:00 — Common mistakes teams still make
- 53:00 — Closing: discipline beats stack fashion
- 55:00 — End
Transcript
[0:00]Valerii: Welcome back to Builder Notes. Today we are staying with Django, but we are changing the angle. The last conversation was about modern Django as a practical framework. This one is about production Django: the version of Django that has real users, real permissions, real security problems, real background jobs, real database migrations, and real support tickets when something goes wrong.
[0:48]Valerii: Tutorial Django is clean. Production Django is not. Tutorial Django has a model, a view, a template, and a happy path. Production Django has old data, staff users, forgotten permissions, slow queries, third-party packages, audit requirements, AI-generated pull requests, and one migration that everyone is afraid to run. That is the Django we are talking about today.
[1:28]Valerii: Our guest is Arjun Mehta, a principal backend engineer who has worked on Django systems in finance, education, internal operations, and B2B SaaS. He has strong opinions, but they are not framework-fan opinions. They are production opinions. Arjun, welcome.
[1:50]Arjun Mehta: Thanks for having me. I like the distinction you made because a lot of Django debates are too abstract. People argue whether Django is old, whether it is fast enough, whether it is cool enough. In production, the questions are different. Can we patch it? Can we audit it? Can we explain the data model? Can support fix a customer issue without asking engineering every time? Can we run the migration without taking the app down? Those questions are where Django either proves itself or exposes bad engineering habits.
[2:30]Valerii: Let us start there. What separates a real Django app from a demo?
[2:38]Arjun Mehta: A demo proves that the happy path exists. A real app proves that the unhappy paths are controlled. In a demo, a user signs up, creates a project, and sees a dashboard. In production, a user forgets a password, changes email, loses access, gets invited to the wrong organization, uploads a broken CSV, clicks twice, leaves the company, asks for data deletion, and then support needs to know what happened. Production Django is about designing for those moments.
[3:36]Valerii: So the framework is not the finish line.
[3:40]Arjun Mehta: Exactly. Django gives you good defaults and strong building blocks, but it will not make judgment calls for you. It will not decide your permission model. It will not decide whether your audit log is good enough. It will not decide whether staff users should be able to impersonate customers. Those are product and engineering decisions. Django helps you implement them clearly if you respect the system.
[4:28]Valerii: What does respecting the system mean?
[4:32]Arjun Mehta: It means learning Django’s conventions before fighting them. Use models carefully. Use migrations carefully. Understand querysets. Understand forms. Understand middleware. Understand the admin. Understand settings. Too many teams treat Django as a folder structure where they can dump any pattern from any other stack. Then they blame Django when the app becomes confusing.
[5:00]Valerii: Django 6.0 brought security back into the visible conversation with built-in Content Security Policy tools. Explain why that matters.
[5:10]Arjun Mehta: Content Security Policy, or CSP, is a browser security control that helps limit where scripts, images, styles, and other resources can load from. In practical terms, it can reduce the damage of certain injection problems, especially cross-site scripting. Before built-in support, many Django teams used third-party packages or custom middleware. Having first-party tools makes CSP feel like part of normal Django security work rather than an optional advanced add-on.
[6:10]Valerii: Does built-in support mean teams are secure automatically?
[6:14]Arjun Mehta: No. That is the dangerous misunderstanding. A framework can expose the tool, but the team still has to design the policy. You need to know which domains your app actually needs. You need to deal with inline scripts, third-party analytics, payment widgets, image hosts, and admin pages. CSP is not a checkbox. It is a policy that reflects how your frontend actually behaves.
[7:10]Valerii: What is the sensible way to adopt it?
[7:15]Arjun Mehta: Start in report-only mode if the app is already live. Collect violations. Find the scripts and assets your pages use. Remove what you do not need. Then tighten the policy gradually. If you turn on a strict policy blindly, you may break the product. If you never turn it on, you leave protection on the table. The disciplined path is observe, simplify, enforce.
[8:00]Valerii: Let us make CSP less abstract. What does a normal Django team actually do on Monday morning?
[8:08]Arjun Mehta: They inventory their pages. Public marketing pages, logged-in app pages, admin pages, payment pages, embedded media, static files, user-uploaded media. Then they ask: what resource sources do we truly need? Can we remove inline JavaScript? Can we use nonces where needed? Are we loading random scripts from old vendors? CSP forces a cleanup conversation that many teams avoid.
[9:12]Valerii: That sounds like security becoming product maintenance.
[9:16]Arjun Mehta: That is exactly what it is. Good security is not only emergency response. It is regular maintenance. Django has always cared about secure defaults, but production teams still need habits: security updates, dependency review, headers, permissions, logging, backups, and incident drills. CSP is one visible piece of a bigger discipline.
[10:18]Valerii: What is the mistake you see with security headers?
[10:22]Arjun Mehta: Copying a config from a blog and never testing it. Security headers are not decorations. They affect browser behavior. You need to understand what each one does, what it breaks, and how it interacts with your app. Django gives you settings and middleware, but the team has to own the decision.
[11:00]Valerii: Another Django 6.0 feature people are talking about is template partials. Why should anyone care about something that sounds so small?
[11:10]Arjun Mehta: Because small template improvements can change how teams build interfaces. Template partials let you define reusable named fragments inside templates. That matters when you are building server-rendered pages with small dynamic sections: table rows, cards, form fragments, status panels, filters. It gives teams a cleaner way to organize template pieces without exploding the number of files or reaching immediately for a heavy frontend.
[12:15]Valerii: So this connects to the return of server-rendered apps.
[12:20]Arjun Mehta: Yes. Many products need interactivity, but not every product needs a full single-page application. Django templates, partials, and lightweight JavaScript can be enough for dashboards, internal tools, admin-like workflows, approval queues, reports, and CRUD-heavy SaaS products. The win is not ideological. The win is fewer moving parts.
[13:15]Valerii: Where do partials help most?
[13:18]Arjun Mehta: They help where the same piece of UI appears in multiple states. A task row before and after completion. A user card in search results and on a detail page. A validation summary after a form post. A notification item. A billing status badge. These are small pieces, but if you manage them poorly, templates become messy fast.
[14:00]Valerii: You said fewer moving parts. Why are some teams reconsidering heavy frontends?
[14:08]Arjun Mehta: Because heavy frontends are not free. You add a build pipeline, state management, API contracts, frontend routing, authentication edge cases, duplicated validation, separate error handling, and often another deployment path. Sometimes that is worth it. If you are building Figma, Notion, Linear, or a highly interactive product, yes, you need serious frontend architecture. But if you are building a compliance dashboard or a finance approval queue, a full SPA may be unnecessary weight.
[15:20]Valerii: What is the practical decision rule?
[15:24]Arjun Mehta: Ask where the product complexity lives. If it lives mostly in data rules, permissions, workflows, and forms, Django templates can go very far. If it lives in client-side interaction, offline state, live collaboration, or rich canvas behavior, use a serious frontend. The mistake is choosing the frontend architecture before understanding the product shape.
[16:20]Valerii: So the new Django story is not anti-frontend.
[16:24]Arjun Mehta: No. It is anti-default-complexity. Use the browser well. Use JavaScript well. Just do not turn every settings page into an app within an app.
[17:00]Valerii: The 2025 Django survey shows a lot of interest in type hints. What is your take on typing in Django?
[17:10]Arjun Mehta: Type hints are useful when they clarify boundaries. Services, utility functions, task inputs, API serializers, settings objects, and domain logic can benefit a lot. But teams should not turn typing into theater. If your type hints are wrong, ignored, or impossible to maintain, they become noise. The goal is not to make Django feel like another language. The goal is to reduce mistakes in places where mistakes are expensive.
[18:15]Valerii: Where would you start?
[18:18]Arjun Mehta: Start at the edges. Function inputs. Return values for business logic. Task arguments. Integration clients. Anything that crosses a boundary. I care less about annotating every tiny local variable and more about making it clear what a function expects and guarantees.
[19:05]Valerii: Does typing fight Django’s dynamic nature?
[19:09]Arjun Mehta: Sometimes there is friction. Django is dynamic. Querysets, models, managers, settings, and forms can be hard to type perfectly. But partial typing is still valuable. You do not have to achieve mathematical purity to get practical safety. A little clarity in the right place beats a massive typing project that nobody trusts.
[20:00]Valerii: The survey also shows AI tools becoming part of Django learning and development. What are you seeing in real teams?
[20:10]Arjun Mehta: AI is now a normal assistant for many developers. People use it to generate boilerplate, explain errors, draft tests, write migrations, review unfamiliar code, or remember syntax. That is useful. The danger is when developers treat AI output as authority. Django has specific conventions and security implications. AI can produce code that looks plausible and is subtly wrong.
[21:15]Valerii: Give me an example.
[21:18]Arjun Mehta: Permissions are a common one. AI might generate a view that checks whether the user is authenticated, but not whether the user belongs to the organization they are trying to access. The code runs. The test might pass if the test is shallow. But the app leaks data. That is not a syntax problem. That is a product security problem.
[22:10]Valerii: So AI makes weak review more dangerous.
[22:14]Arjun Mehta: Exactly. AI can speed up good engineers because they know what to reject. It can also speed up bad assumptions. The review process matters more, not less.
[23:00]Valerii: How should a team review AI-generated Django code?
[23:08]Arjun Mehta: First, require the same standards as human code. Does it follow the project’s patterns? Are permissions correct? Are queries efficient? Are forms validating server-side? Are migrations safe? Are tests meaningful? Second, ask what the code assumes. AI-generated code often hides assumptions because it writes confidently. Third, compare with official docs when the code touches security, async, tasks, authentication, migrations, or deployment.
[24:20]Valerii: What is a bad use of AI?
[24:24]Arjun Mehta: Using it to replace understanding. If a developer cannot explain the generated code, they should not merge it. Especially in Django, where a few lines can affect permissions, database writes, CSRF behavior, or admin access.
[25:12]Valerii: What is a good use?
[25:15]Arjun Mehta: Generating a first draft of repetitive code, writing a basic test scaffold, summarizing release notes, explaining a traceback, comparing two approaches, or creating a checklist for a migration. AI is useful as a junior assistant with infinite patience. It is not a senior engineer with accountability.
[26:00]Valerii: Let us talk about PostgreSQL. Why does it remain such a strong default for Django teams?
[26:08]Arjun Mehta: PostgreSQL fits Django’s strengths. Relational modeling, constraints, transactions, indexes, JSON fields when needed, full-text search for many cases, and mature operational tooling. A lot of Django apps are business systems. Business systems usually have relationships and rules. PostgreSQL is very good at enforcing rules close to the data.
[27:10]Valerii: What is the most common data modeling mistake?
[27:14]Arjun Mehta: Treating the database like a dumb storage layer. If the rule matters, consider whether the database should enforce it. Unique constraints, foreign keys, not-null constraints, check constraints, and indexes are not optional decoration. They are part of the product’s truth.
[28:06]Valerii: Where do teams overdo it?
[28:10]Arjun Mehta: They sometimes model too abstractly too early. Generic foreign keys everywhere, flexible JSON blobs for core data, status fields with no clear transitions, and soft deletion that nobody fully understands. Flexibility feels safe at first, but it often moves confusion into runtime.
[29:00]Valerii: You care a lot about Django admin. Why?
[29:06]Arjun Mehta: Because the admin is where internal reality shows up. Support, operations, finance, moderation, content, and engineering all touch it. A careless admin can cause real damage. A thoughtful admin can prevent mistakes, speed up support, and make the business more observable.
[30:00]Valerii: What makes an admin thoughtful?
[30:04]Arjun Mehta: Clear list displays, useful filters, safe search, read-only sensitive fields, permission-aware actions, links to related records, timestamps, status history, and warnings before destructive operations. Also, naming matters. Internal users should not have to understand database jargon to do their job.
[31:05]Valerii: So admin customization is not just developer convenience.
[31:09]Arjun Mehta: Correct. It is internal UX. If the admin is bad, support creates spreadsheets. Then engineering loses the source of truth. Then the business runs on side channels. A good admin keeps operations close to the actual data.
[32:00]Valerii: Permissions and audit logs are where many systems quietly fail. How should Django teams approach them?
[32:10]Arjun Mehta: Start with the organization model. Who owns what? Who can see what? Who can change what? What should staff users do? What should they never do? Then make those rules explicit in code and tests. Do not scatter permission logic randomly across views, templates, serializers, and admin actions without a pattern.
[33:10]Valerii: And audit logs?
[33:13]Arjun Mehta: Audit logs answer the question: what happened? Who changed the billing email? Who approved the payout? Who disabled the account? Who exported data? If support or compliance needs that answer, you cannot rely on memory. You need structured records.
[34:05]Valerii: What should not go into an audit log?
[34:08]Arjun Mehta: Sensitive secrets, raw passwords, unnecessary personal data, and noisy events nobody will use. Audit logs should be useful, not a landfill. Log what helps reconstruct important decisions.
[35:00]Valerii: Django Tasks came up in the previous episode, but let us connect it to production discipline. What changes with first-party task definitions?
[35:10]Arjun Mehta: The big change is vocabulary. Django now gives teams a standard way to define and enqueue background work. That is good because background work is everywhere: emails, imports, reports, cleanup, notifications, integrations. But production teams still need external execution infrastructure. A task definition does not magically run itself in a reliable queue.
[36:12]Valerii: What does a reliable task design include?
[36:16]Arjun Mehta: Idempotency, status, retries, observability, clear inputs, safe failure behavior, and user-facing feedback when needed. If a report task fails, the user should not stare at a spinner forever. If an email task retries, it should not spam the customer. If an import partially succeeds, the system should know what happened.
[37:15]Valerii: What is the wrong mindset?
[37:18]Arjun Mehta: The wrong mindset is treating background tasks as a junk drawer. Slow code goes there. Confusing code goes there. Risky code goes there. That is how teams create invisible failure. Background work needs more design, not less.
[38:00]Valerii: Testing. What should Django teams test that they usually do not?
[38:08]Arjun Mehta: Permission boundaries. Admin actions. Failed forms. Duplicate submissions. Migration behavior. Background task retries. Data exports. Organization scoping. Most teams test whether the happy path returns 200. That is not enough. Real bugs hide where business rules meet edge cases.
[39:08]Valerii: What is an example of a permission test that matters?
[39:12]Arjun Mehta: User A belongs to Organization A. User B belongs to Organization B. User A should never access Organization B’s invoice by guessing an ID. That sounds obvious, but ID-based access bugs happen constantly. Write the test. Keep writing it for every sensitive object.
[40:05]Valerii: What about testing the admin?
[40:08]Arjun Mehta: If admin actions can change important data, test them. If staff roles have different permissions, test them. The admin is production code. Treat it that way.
[41:00]Valerii: You describe migrations as production events. What does that mean?
[41:08]Arjun Mehta: It means a migration is not just a file generated by makemigrations. It is a change to a live database. It can lock tables, backfill data, fail halfway, or expose old code to new schema. Teams should plan migrations, especially on large tables. Split risky changes. Test with realistic data. Know how to roll forward.
[42:10]Valerii: Roll forward, not roll back?
[42:13]Arjun Mehta: Often, yes. Rollbacks sound comforting, but database state can make them complicated. You should know your rollback options, but you should also have a roll-forward plan. If a nullable column was added safely, fine. If a destructive data migration ran, rollback may not be simple. Production thinking means admitting that before the deploy.
[43:12]Valerii: What is the migration habit you wish every team had?
[43:16]Arjun Mehta: Review generated migrations like code. Do not blindly commit them. Ask what SQL they imply, what data volume they touch, and whether old and new app versions can coexist during deploy.
[44:00]Valerii: Let us return to architecture. Templates, APIs, or separate frontend: how do you decide?
[44:08]Arjun Mehta: Use templates when the interaction is mostly request-response and the server owns the workflow. Use APIs when you have real API consumers: mobile apps, partner integrations, separate frontend teams, or public developer access. Use a separate frontend when the client-side experience is the product. Do not choose an API just because it sounds more modern.
[45:12]Valerii: What is the hidden cost of API-first?
[45:16]Arjun Mehta: You create two products: the backend API and the frontend client. Now validation, errors, authentication, permissions, and versioning need more coordination. That can be worth it. But if the only client is your own web page, it may be unnecessary ceremony.
[46:08]Valerii: What is the hidden cost of templates?
[46:12]Arjun Mehta: If you push templates beyond their natural shape, you can create tangled UI logic. You still need discipline. Keep views clear. Keep templates readable. Use partials carefully. Do not hide complex business rules in template conditionals.
[47:00]Valerii: Give us your production Django checklist.
[47:06]Arjun Mehta: Supported Django version. Security update process. Clear settings per environment. PostgreSQL backups tested. Error tracking installed. Structured logging. Health checks. Permission tests. Admin actions reviewed. Migrations reviewed. Static and media files handled properly. CSP and security headers understood. Background tasks observable. Dependencies audited. Deployment documented. That sounds like a lot, but most of it is basic hygiene.
[48:20]Valerii: What would you check first in a messy existing project?
[48:24]Arjun Mehta: Version support, backups, permissions, and deploy process. Those are survival issues. After that, I look at slow queries, package risk, admin safety, and test coverage around money or private data.
[49:10]Valerii: What does good observability look like for a small Django team?
[49:15]Arjun Mehta: You do not need a giant platform on day one. You need error tracking, useful logs, request timing, database visibility, task status, and alerts for things that matter. The goal is simple: when a user reports a problem, you should be able to investigate without guessing.
[50:00]Valerii: Common mistakes. What do Django teams still get wrong?
[50:07]Arjun Mehta: They put business logic everywhere. They trust the admin too much without permissions. They use signals for hidden workflows that should be explicit. They add Celery or queues without designing task state. They skip database constraints. They use AI-generated code without review. They treat migrations casually. They build a separate frontend before proving they need one.
[51:10]Valerii: Signals are controversial. What is your position?
[51:14]Arjun Mehta: Signals are useful for some decoupled events, but they become dangerous when they hide important business behavior. If saving an invoice secretly sends money, updates analytics, emails the customer, and changes account status through signals, debugging becomes painful. Important workflows should be visible.
[52:05]Valerii: What is your advice to a team starting a Django app today?
[52:10]Arjun Mehta: Start simple, but not sloppy. Use Django’s strengths: models, forms, admin, auth, templates, migrations, tests. Add APIs, async, tasks, AI tools, and frontend complexity when the product earns them. Read the official docs. Review generated code. Protect user data. Make operations visible. That is the difference between fast and reckless.
[53:00]Valerii: Let us close with the big lesson. What does Django still teach the industry?
[53:08]Arjun Mehta: Django teaches that boring is not the opposite of modern. Boring can mean integrated, documented, secure, maintainable, and understandable. A mature framework lets you spend less time inventing plumbing and more time modeling the actual business. But you only get that benefit if you practice discipline.
[54:05]Valerii: So production Django is not just Django plus users.
[54:09]Arjun Mehta: Right. Production Django is Django plus responsibility. Responsibility for security, data, permissions, migrations, background work, staff tools, and the people who rely on the system.
[54:36]Valerii: Arjun Mehta, thank you for joining us.
[54:40]Arjun Mehta: Thanks for having me.
[54:45]Valerii: For listeners, the takeaway is simple: do not ask whether Django is old or new. Ask whether your team is disciplined enough to use it well. That is Builder Notes. Thanks for listening.
[55:00]Valerii: End.