Skip to content

Django Framework

170 companion flashcards · AI-assisted study content · Open the deck →

This deck walks you through the core building blocks of Django, one of the most popular Python web frameworks. The cards cover foundational concepts like the MTV pattern, project and app structure, and move into practical territory such as defining models, working with the ORM to query a database, running migrations, and choosing between function-based and class-based views. Together they give you a solid mental map of how a Django application fits together from request to response.

It is a great fit if you are new to Django and want a structured way to learn the essentials, or if you have some experience but want to firm up the terminology and commands you reach for every day. If you are comfortable with basic Python, you will get the most out of these cards, since the questions assume you can read small snippets of code and follow along in your own project as you study.

To make the material really stick, try answering a card, then immediately opening a terminal and trying the related command or writing a quick model of your own. Spacing your review over several short sessions rather than one long cramming block tends to work well for framework knowledge, because you give your brain time to connect each piece with hands-on practice. Revisiting tricky areas like the difference between filter() and get(), or when to use FBVs versus CBVs, after a day or two will help the patterns feel natural when you start building your own applications.

Django Fundamentals and Project Layout

Django is a high-level Python web framework designed for rapid development and clean, pragmatic design. It follows the Model-Template-View (MTV) architectural pattern, which separates concerns by placing data structure in Models, presentation logic in Templates, and business logic in Views. Django ships with many built-in features out of the box, including an Object-Relational Mapper (ORM), an auto-generated admin interface, an authentication system, and a templating engine, making it a batteries-included framework for building web applications.

A Django project is created using the command django-admin startproject myproject, which generates the project directory containing several key files. The manage.py file is a thin wrapper around django-admin that sets the DJANGO_SETTINGS_MODULE to the project's settings.py and serves as the recommended entry point for project-level commands. The wsgi.py file exposes a WSGI-compatible callable used by production servers like Gunicorn or uWSGI for synchronous request handling, while asgi.py exposes an ASGI-compatible callable for servers like Daphne or Uvicorn, enabling async views, WebSockets, and long-lived connections through Django Channels. The settings.py file is the central configuration module containing settings such as INSTALLED_APPS, MIDDLEWARE, DATABASES, TEMPLATES, STATIC_URL, MEDIA_URL, ALLOWED_HOSTS, and SECRET_KEY.

Within a project, individual features are organized into apps, which are self-contained Python packages. An app is created with python manage.py startapp myapp and must be added to the INSTALLED_APPS list in settings.py to be registered with the project. Each app contains its own models.py, views.py, urls.py, admin.py, tests.py, and apps.py. The apps.py file holds the AppConfig subclass for the app, which can run startup code in its ready() method, such as registering signals. A project contains many apps, and a well-designed app can be reused across different projects by placing it on the PYTHONPATH and including it in INSTALLED_APPS. The root URL configuration in the project's urls.py typically delegates to app-level urls.py files using the include() function.

Models, ORM, and Migrations

Django models are Python classes that subclass django.db.models.Model, with each model mapping to a single database table and each class attribute representing a database column. The framework provides a rich set of field types to handle different kinds of data: CharField for short text requiring a max_length, TextField for longer text, IntegerField for integers, BooleanField for True/False values, DateTimeField for date and time values, ForeignKey for many-to-one relationships, and ManyToManyField for many-to-many relationships. Additional behavior can be configured at the field level using null=True to allow NULL values at the database column level, and blank=True to permit empty values in forms.

A model can also include a Meta inner class to hold model-level options that do not define database fields but affect the model's behavior. Common Meta options include ordering for default queryset ordering, verbose_name for human-readable naming, db_table to override the table name, unique_together for composite uniqueness, indexes for defining database indexes, and constraints for declaring database-level integrity rules such as UniqueConstraint and CheckConstraint. Defining a __str__ method on a model is important because it returns a human-readable string representation used by the Django admin, the shell, and default ModelChoiceField rendering. Adding db_index=True to a field creates a single-column index, while Meta.indexes allows composite indexes for query optimization. The default database backend is SQLite via django.db.backends.sqlite3, while production deployments typically switch to PostgreSQL, MySQL, or Oracle by adjusting the DATABASES setting.

Relationships between models are defined using specialized field types. A ForeignKey represents a many-to-one relationship and accepts an on_delete argument that specifies behavior when the referenced object is deleted. Common on_delete options include CASCADE to delete dependents, PROTECT to block deletion, SET_NULL to set the foreign key to NULL (requiring null=True), SET_DEFAULT to set it to a default value, and DO_NOTHING to take no action. The related_name argument sets the reverse accessor name from the related model, defaulting to <modelname>_set if not specified. A OneToOneField represents a strict 1:1 link and is commonly used to extend the User model with a Profile. A ManyToManyField creates an auto-generated join table, but a custom through model can be specified to store additional fields on the relationship. Migrations are Django's version-controlled changes to the database schema, created with python manage.py makemigrations and applied with python manage.py migrate, with rollback possible by specifying a previous migration name.

Advanced Querying and Optimization

The Django ORM lets developers interact with the database using Python code rather than raw SQL. The default manager on every model is objects, and the all() method returns a QuerySet containing all rows in the table. To narrow results, filter() returns a QuerySet of zero or more objects, while get() returns a single object or raises DoesNotExist or MultipleObjectsReturned exceptions. The exclude() method is the inverse of filter(), returning objects that do not match the given criteria. Field lookups support powerful queries using double-underscore syntax, such as title__icontains='django', date__gte=some_date, and author__name='Alice', enabling complex searches without writing SQL directly.

Several QuerySet methods help optimize database access. The count() method issues a SELECT COUNT(*) query, which is far cheaper than using len(queryset), which forces evaluation of the full queryset. The exists() method is even more efficient when only the presence of records is needed, as it issues a fast SELECT 1 ... LIMIT 1 query. The values() method returns dictionaries of field values, while values_list() returns tuples; with flat=True and a single field, values_list() returns a flat list. The only() and defer() methods control which fields are loaded from the database, useful for avoiding unnecessary I/O on large TextField columns.

Django provides several expression types for advanced queries. The Q object enables complex lookups with OR, AND, and NOT operators, since multiple filter() arguments are combined with AND by default. The F expression references a model field value directly in the database, avoiding a Python round-trip, which is critical for atomic operations like Article.objects.update(views=F('views') + 1). The aggregate() method returns a dictionary of aggregated values using functions like Count, Avg, and Sum, while annotate() adds aggregated fields to each object in the queryset. Subqueries can be embedded using Subquery() and Exists() from django.db.models, often paired with OuterRef() to reference the outer query. The N+1 query problem, which occurs when accessing related objects in a loop triggers one extra query per parent row, is typically solved using select_related() for ForeignKey and OneToOneField relationships, and prefetch_related() for ManyToManyField and reverse relations. For data integrity, transaction.atomic groups multiple SQL operations so they commit or roll back atomically, while select_for_update() locks selected rows for the duration of a transaction to prevent race conditions. Bulk operations like bulk_create(), queryset update(), and queryset delete() allow efficient batch modifications.

Views, URLs, and Responses

Django views are Python callables that take an HttpRequest and return an HttpResponse. Function-based views (FBVs) are simple Python functions, while class-based views (CBVs) subclass django.views.View and map HTTP methods to class methods like get() and post(). The CBV is registered in URL configuration by calling its as_view() classmethod. Django's generic class-based views handle common patterns out of the box, including ListView for displaying lists of objects, DetailView for displaying a single object, CreateView, UpdateView, and DeleteView for the corresponding CRUD operations. These views are imported from django.views.generic. For example, ListView accepts a paginate_by attribute to enable pagination, passing page_obj and paginator to the template and reading the page from the ?page= query parameter.

URL routing is configured in urls.py using the urlpatterns list. The path() function maps URL patterns to views, and include() is used to delegate to app-level URL configurations. Path converters capture parts of the URL as typed parameters, with built-in converters including int for integers, str for non-empty strings excluding /, slug for slugs, and uuid for UUIDs. The reverse_lazy function returns a URL string evaluated lazily, which is required when referencing URL reverses in module-level code such as success_url attributes on class-based views, because URLs are not loaded yet at import time. The {% url %} template tag resolves a named URL pattern to its path, accepting either positional or keyword arguments.

The django.shortcuts module provides convenient helpers to keep views concise. render() combines loading a template, populating context, and returning an HttpResponse. redirect() returns an HttpResponseRedirect (302) to a resolved URL, a named URL pattern, or a model instance with get_absolute_url(). get_object_or_404() returns an object or raises Http404, which is preferred over get() in views because Django's 404 handler renders a friendly page. HttpResponse is the base class for all responses, with subclasses including JsonResponse for JSON data, FileResponse for streaming files without loading them fully into memory, and StreamingHttpResponse for streaming iterators like CSV exports. Several view decorators enhance behavior: @require_http_methods rejects unsupported methods with a 405, @login_required restricts access to authenticated users, @cache_page caches the full response, and @condition enables HTTP conditional GETs for efficient 304 responses. The never_cache decorator ensures the response is not cached, while @vary_on_headers appends header names to the Vary response.

Templates and the Presentation Layer

Django's template engine uses HTML files with special syntax to separate presentation from logic. Variables are output using double curly braces like {{ variable }}, template tags use curly-brace percent syntax like {% tag %} for control flow, and filters transform values using the pipe syntax like {{ value|filter }}. Common built-in filters include lower, truncatewords, default, safe for marking unescaped HTML, and date for date formatting. Filters can be chained, allowing expressions like {{ value|lower|truncatechars:30 }}. Templates are stored in the app's templates/ directory and loaded with the {% load %} tag, such as {% load static %} for static file references or {% load myfilters %} for custom template filters. Custom template filters are registered through a templatetags/ module using the @register.filter decorator.

Template inheritance is a powerful feature for promoting the DRY (Don't Repeat Yourself) principle. A base template defines {% block %} placeholders that child templates override, and child templates start with {% extends "base.html" %} followed by their own block definitions. The {% include %} tag renders another template inline with optional context, ideal for reusable snippets like partials. Context is passed to a template from a view as a dictionary via render(request, 'template.html', context), making each variable accessible by its key. Inside {% for %} loops, the forloop object exposes useful properties: forloop.counter for 1-indexed counting, forloop.first and forloop.last for boundary checks, and forloop.parentloop for accessing the outer loop context. The {% empty %} clause inside a {% for %} block renders a fallback when the iterable is empty.

Context processors are functions that automatically inject variables into every template context. They are configured in the TEMPLATES setting under OPTIONS.context_processors. Built-in processors include django.template.context_processors.request, which adds the request object, auth which adds user and perms, and messages for the messages framework. Custom context processors are simple Python functions that take a request and return a dictionary. The {% csrf_token %} tag inserts a hidden input containing the CSRF token bound to the user's session, required inside every POST form. The messages framework provides a one-time notification system, where views call messages.success(request, 'Saved!') and templates iterate over {% if messages %} blocks to display them; messages are stored in the session or cookie and shown only once, with MESSAGE_STORAGE defaulting to SessionStorage.

Forms, Admin, and Authentication

Django forms handle HTML form rendering, validation, and data cleaning through Python classes. A form is defined by subclassing forms.Form and declaring fields like CharField and EmailField. The form.is_valid() method triggers validation, and form.cleaned_data provides access to the validated, converted data. A ModelForm automatically generates form fields from a model by specifying a Meta class with model and fields, and calling form.save() directly creates or updates the corresponding database record. Validation occurs at multiple layers: field-level validation uses built-in validators and clean_<fieldname>() methods, form-level validation is handled in the clean() method for cross-field rules, and model-level validation is implemented on the model itself, with errors stored in form.errors.

The Django admin is an auto-generated web interface for managing data, available at /admin/ after creating a superuser with python manage.py createsuperuser. Models are registered in admin.py using admin.site.register(Model), and a ModelAdmin class allows customization of the interface. The list_display attribute controls which columns appear in the list view, list_filter adds sidebar filters, and search_fields enables a search bar. The @admin.register(Model) decorator is an alternative to the explicit register() call. This combination of ModelForm and the admin interface provides a complete content management experience with very little code.

Django's authentication system is provided by django.contrib.auth, which includes a User model storing credentials and profile information, the authenticate() function to verify credentials, and login() and logout() functions to manage sessions. The @login_required decorator restricts a view to authenticated users, redirecting unauthenticated visitors to the login URL, while the LoginRequiredMixin provides the same functionality for class-based views. The UserPassesTestMixin enables custom authorization by calling a test_func() method. For anonymous visitors, request.user returns an AnonymousUser instance with is_authenticated == False. Django includes a permission system with per-object and per-model permissions, accessed via the @permission_required decorator following the <app_label>.<action>_<modelname> naming convention. Groups bundle permissions and assign them to multiple users at once. A custom user model is created by subclassing AbstractUser or AbstractBaseUser and setting AUTH_USER_MODEL in settings, but this must be done before the first migration. Passwords are hashed using PBKDF2 with SHA256 by default, with user.set_password('new') and user.save() used to update; the default iteration count is 600,000 since Django 4.1, with argon2 or bcrypt as recommended alternatives for stronger security.

Middleware, Security, and File Handling

Middleware in Django is a framework of hooks that processes requests and responses globally. Each middleware is added to the MIDDLEWARE setting in settings.py and is executed in order for requests, then in reverse order for responses. Built-in middleware classes include SecurityMiddleware for HTTPS redirects and HSTS headers, SessionMiddleware for session support, CommonMiddleware for URL rewriting, CsrfViewMiddleware for CSRF protection, AuthenticationMiddleware for attaching request.user, and MessageMiddleware for flash messages. Custom middleware can be created as a factory function returning a callable that wraps request, or by subclassing MiddlewareMixin for the older style with process_request and process_response methods. The ClickjackingMiddleware sets the X-Frame-Options header, while GZipMiddleware compresses responses for browsers that send Accept-Encoding: gzip and must be placed near the top of the middleware list to compress content produced by other components.

Django includes comprehensive built-in security features. CSRF protection uses a token-based system, with the {% csrf_token %} template tag inserting a hidden input bound to the user's session and CsrfViewMiddleware verifying the submitted token matches the one in the session. The CSRF cookie is named csrftoken by default and is configurable via CSRF_COOKIE_NAME, with CSRF_COOKIE_HTTPONLY controlling JavaScript access. XSS protection is automatic through template escaping, and SQL injection is prevented via parameterized ORM queries. The SECURE_BROWSER_XSS_FILTER setting emits the X-XSS-Protection header, SECURE_HSTS_SECONDS enables HTTP Strict Transport Security, and SECURE_CONTENT_TYPE_NOSNIFF prevents MIME-sniffing. Passwords are hashed using PBKDF2 with a per-user salt, and SECRET_KEY is used for signing cookies and tokens, which should be loaded from an environment variable rather than committed to version control. The DEBUG setting should be False in production to prevent leaking settings and environment variables through detailed tracebacks.

Static files such as CSS, JavaScript, and images are configured in settings.py with STATIC_URL, STATICFILES_DIRS, and STATIC_ROOT. The {% load static %} template tag and {% static 'path/to/file' %} tag are used to reference static files in templates, and python manage.py collectstatic gathers all static files into STATIC_ROOT for production deployment. Media files for user uploads are configured with MEDIA_URL and MEDIA_ROOT, with FileField and ImageField used in models to handle file storage. During development, media files can be served by adding a static() URL helper to urlpatterns. The ALLOWED_HOSTS setting restricts which Host headers Django accepts, returning an HTTP 400 for unrecognized hosts and preventing HTTP Host header attacks.

DRF, Signals, Testing, and More

Django REST Framework (DRF) is a powerful toolkit for building Web APIs on top of Django. Its key components include Serializers for converting models to and from JSON, ViewSets for grouping related API views, Routers for auto-generating URL patterns, multiple authentication options including token, session, and JWT, and a browsable API web interface for testing. A serializer converts complex data types like models and querysets to native Python types for JSON rendering and vice versa. The Serializer class requires manual field definition and custom create() and update() methods, while the ModelSerializer automatically generates fields from a model and provides default implementations, also auto-generating validators based on model constraints.

Signals allow decoupled components to be notified when certain actions occur. Common built-in signals include pre_save and post_save for before and after model saves, pre_delete and post_delete for deletions, and request_started and request_finished for request lifecycle events. Signals are connected using the @receiver(post_save, sender=MyModel) decorator. Custom signals can be created using django.dispatch.Signal(), sent with the send() method, and received by functions decorated with @receiver. This pattern is useful for triggering side effects like sending confirmation emails or invalidating caches when model events occur.

Django's testing framework extends Python's unittest with TestCase, and tests are run with python manage.py test. The test Client simulates HTTP requests without a running server, handling cookies, sessions, and redirects automatically. The Django cache framework supports various backends including Redis, Memcached, locmem, db, and filebased, configured via the CACHES setting. The low-level cache API uses cache.set, cache.get, cache.get_or_set, and cache.delete, with None as the timeout meaning cache forever. The @cache_page decorator caches entire view responses, while the {% cache %} template tag caches fragments. Cache invalidation patterns include deleting keys after saves, using versioned keys, and clearing cache through signals. Sessions store arbitrary data per visitor on the server side, accessible via request.session, with multiple backends available. Management commands extend Django's CLI by placing a Command class in myapp/management/commands/, accepting arguments through add_arguments(). The send_mail() helper and EmailMessage class provide email functionality, with the console backend printing emails to stdout during development and the locmem backend capturing them in mail.outbox for testing. Internationalization uses gettext_lazy to mark translatable strings, with makemessages and compilemessages commands generating .po and .mo files. Specialized fields like JSONField store arbitrary JSON with key lookups for queries, while UUIDField stores 128-bit UUIDs, often paired with <uuid:id> path converters for type-safe routing. The auto_now and auto_now_add options on DateTimeField automatically track creation and modification timestamps, and timezone.now() should be preferred over datetime.now() when USE_TZ is enabled.

Frequently asked questions

What is Django?

Django is a high-level Python web framework that encourages rapid development and clean, pragmatic design. It follows the MTV (Model-Template-View) architectural pattern and includes built-in features like an ORM, admin interface, and authentication system.

What is the Django template language?

Django's template engine uses HTML files with special syntax:
  • {{ variable }} – output a variable
  • {% tag %} – template tags for logic (if, for, block)
  • {{ value|filter }} – apply filters like date, length, lower
Templates are stored in the app's templates/ directory.

How do you serve static files in Django?

Configure in settings.py:
STATIC_URL = '/static/'
STATICFILES_DIRS = [BASE_DIR / 'static']
STATIC_ROOT = BASE_DIR / 'staticfiles'

In templates use {% load static %} and {% static 'css/style.css' %}. Run python manage.py collectstatic for production.

What is the role of manage.py?

manage.py is a thin wrapper around django-admin that sets the DJANGO_SETTINGS_MODULE to the project's settings.py. It is the recommended entry point for project-level commands like migrate, runserver, and shell.

What is the difference between null=True and blank=True?

null=True allows NULL at the database column level; blank=True allows the field to be empty in forms. Common pattern:
description = models.TextField(null=True, blank=True)
For string-based fields, prefer blank=True alone (empty string instead of NULL).

How do you bulk create objects in Django?

Use bulk_create():
Article.objects.bulk_create([
  Article(title='A'), Article(title='B')
])

It issues a single INSERT and skips per-row save() signals.

What is the messages framework?

django.contrib.messages is a one-time notification system. In views:
messages.success(request, 'Saved!')
In templates: {% if messages %}{% for m in messages %}<div class="alert">{{ m }}</div>{% endfor %}{% endif %}
Messages are stored in the session or cookie and shown once.

What is CSRF_COOKIE_HTTPONLY?

CSRF_COOKIE_HTTPONLY = True prevents JavaScript from reading the CSRF cookie via document.cookie. The CSRF token is still submitted via form input, so this does not break forms.

What is StreamingHttpResponse?

StreamingHttpResponse accepts an iterator (e.g. generator) and streams it to the client chunk by chunk. Useful for CSV exports, SSE, or long-running server responses.

How do you create a custom middleware?

A factory function returning a callable that wraps request:
def simple_middleware(get_response):
  def middleware(request):
    response = get_response(request)
    return response
  return middleware

Or subclass MiddlewareMixin for the older style with process_request/process_response.

Drill this topic

170 flashcards on Django Framework — free, no signup needed to start.

Study Django Framework flashcards

LearnWiki pages are generated with AI assistance from LearnCoachAssist's reviewed study catalog and may contain errors — verify anything critical against your course materials.