inertia-django

repository·main·Indexed 20 days ago

https://github.com/inertiajs/inertia-django

A Django adapter for the InertiaJS framework (version 1.2.0) that enables building single-page apps using classic server-side routing and controllers. It provides tools for rendering Inertia responses via decorators or functions, global data sharing, prop serialization with InertiaMeta, and support for optional and deferred props. The package includes InertiaTestCase for specialized assertions and integrates with Vite for frontend asset management.

Tokens
9.3K
Snippets
41
Records
44
Agent score
70%

What's inside inertia-django

  1. Introduction to inertia-django

    main

    The inertia-django adapter enables you to build modern monoliths by connecting a Django backend with a client-side JavaScript framework (such as React, Vue, or Svelte) using Inertia.js.

    Key characteristics:

    • No API required: You write Django code using traditional server-side patterns instead of building a REST or GraphQL API.
    • No client-side routing: Inertia leverages your existing Django routing.
    • Glue, not a framework: It acts as the bridge between your Django server and your frontend framework.
  2. Serialize props using `InertiaMeta`

    main

    Django does not convert objects to JSON by default. While InertiaJsonEncoder handles QuerySets and Models (via model_to_dict), it has limitations (e.g., it excludes editable=False fields like automatic timestamps).

    To gain granular control over serialization, define an InertiaMeta nested class within your model or class. Currently, it supports specifying a fields tuple.

    class User(models.Model):
        name = models.CharField(max_length=255)
        created_at = models.DateField(auto_now_add=True)
    
        class InertiaMeta:
            fields = ('name', 'created_at')
  3. How the resolve callback works

    main

    The resolve callback in createInertiaApp tells Inertia how to load page components. It receives a page name (string) and returns a component module. When using Vite, it is recommended to use import.meta.glob with { eager: true } for eager loading, which results in a single JavaScript bundle.

    // frontend/js/main.js
    createInertiaApp({
        resolve: (name) => {
            const pages = import.meta.glob("../pages/**/*.jsx", { eager: true });
            return pages[`../pages/${name}.jsx`];
        },
        // ...
    });
  4. Use partial reloads for performance optimization

    main

    Partial reloads allow you to request only a subset of props from the server when navigating to the same page component. This reduces payload size and server processing.

    When a partial reload is triggered, the client sends two specific headers:

    • X-Inertia-Partial-Data: A comma-separated list of the specific prop keys requested (e.g., events,auth).
    • X-Inertia-Partial-Component: The name of the component being reloaded.

    The server will then return a JSON response containing only the requested props within the props object.

    # Partial Reload Request Example
    REQUEST
    GET: http://example.com/events
    X-Inertia: true
    X-Inertia-Partial-Data: events
    X-Inertia-Partial-Component: Events
    
    RESPONSE
    HTTP/1.1 200 OK
    Content-Type: application/json
    
    {
      "component": "Events",
      "props": {
        "events": [...]
      },
      "url": "/events/80",
      "version": "c32b8e4965f418ad16eaebba1d4e960f"
    }
  5. How asset versioning works

    main

    Inertia uses asset versioning to ensure clients are always using the latest CSS and JavaScript.

    1. Server-side: You define a version identifier (string, number, or file hash) that changes whenever your assets change.
    2. Client-side: On every Inertia request, the client sends the current version in the X-Inertia-Version header.
    3. Conflict Resolution: If the version in the header does not match the server's current version, the server returns a 409 Conflict response with a X-Inertia-Location header pointing to the correct URL. Inertia then performs a full-page reload to sync the assets.

    Note: 409 Conflict responses are only sent for GET requests. For POST/PUT/PATCH/DELETE requests, a conflict is only triggered if a GET redirect occurs as a result of the request.

    # Conflict Response Example
    REQUEST
    GET: http://example.com/events/80
    X-Inertia: true
    X-Inertia-Version: 6b16b94d7c51cbe5b1fa42aac98241d5
    
    RESPONSE
    409: Conflict
    X-Inertia-Location: http://example.com/events/80
  6. Use the Inertia test client for JSON assertions

    main

    The InertiaTestCase includes a specialized self.inertia client. This client automatically pre-sets the necessary Inertia headers to simulate an Inertia request.

    Note: When using self.inertia, the specialized Inertia assertions (like assertComponentUsed) are not enabled. Use the self.inertia client only when you want to perform standard Django assertions against the raw JSON response.

    # Inside an InertiaTestCase
    self.inertia.get('/events/')
  7. Understand the Inertia protocol lifecycle

    main

    The Inertia protocol operates in two distinct modes depending on the request type:

    1. Initial Load (Full-page request): The very first request to an Inertia app is a standard browser request. The server responds with a full HTML document containing a root <div> (the mounting point) and a data-page attribute. This attribute contains a JSON-encoded page object used to boot the client-side framework.

    2. Subsequent Visits (Inertia requests): Once booted, all subsequent navigations are made via XHR. These requests include the X-Inertia: true header. Instead of HTML, the server responds with a JSON payload containing the updated page object.

    Note: Inertia does not perform server-side rendering (SSR) of JavaScript components; it only serves the initial HTML shell and data.

    # Initial Request Example
    REQUEST
    GET: http://example.com/events/80
    Accept: text/html, application/xhtml+xml
    
    RESPONSE
    HTTP/1.1 200 OK
    Content-Type: text/html; charset=utf-8
    
    <html ...>
    <body ...>
    <div id="app" data-page='{"component":"Event","props":{...},"url":"/events/80","version":"..."}'></div>
    </body>
    </html>
  8. How Inertia.js works with Django

    main

    Inertia.js allows you to build single-page applications (SPAs) using Django as your backend and modern JavaScript frameworks (React, Vue, or Svelte) as your view layer.

    Instead of rendering Django templates on the server, your Django controllers return JSON responses containing a JavaScript page component name and its associated data (props).

    The Workflow:

    1. Standard Django: You use Django's existing routing, controllers, middleware, authentication, and data fetching.
    2. Client-side Interception: Instead of full page reloads, Inertia intercepts link clicks (via the <Link> component) or programmatic visits (via router.visit()) and makes them using XHR.
    3. JSON Responses: The server detects the XHR visit and returns a JSON payload instead of HTML.
    4. Dynamic Swapping: The Inertia client-side library receives the JSON, swaps the current page component with the new one, and updates the browser history without a full reload.
  9. Configure CSRF for Inertia Django

    main

    Because Django's default CSRF header names differ from Axios (the library used by Inertia), you must choose one of the following two configuration options to ensure requests are authenticated correctly.

    Option 1: Configure Axios (Frontend)

    In your entry.js file, set the default header and cookie names:

    axios.defaults.xsrfHeaderName = "X-CSRFToken";
    axios.defaults.xsrfCookieName = "csrftoken";

    Option 2: Configure Django (Backend)

    In your settings.py file, update the CSRF settings:

    CSRF_HEADER_NAME = 'HTTP_X_XSRF_TOKEN'
    CSRF_COOKIE_NAME = 'XSRF-TOKEN'
  10. Preserve scroll position using the Link component

    main

    When using the <Link> component instead of the manual router, you can prevent scroll resetting by adding the preserveScroll prop.

    <script setup>
    import { Link } from "@inertiajs/vue3";
    </script>
    
    <template>
        <Link href="/" preserve-scroll>Home</Link>
    </template>
    import { Link } from "@inertiajs/react";
    
    export default () => (
        <Link href="/" preserveScroll>
            Home
        </Link>
    );
    <script>
      import { Link } from '@inertiajs/svelte'
    </script>
    
    <Link href="/" preserveScroll>Home</Link>
  11. Install Inertia client-side dependencies

    main

    Install the Inertia adapter for your chosen frontend framework using npm. Choose the command corresponding to Vue, React, or Svelte.

    npm install @inertiajs/vue3 vue @vitejs/plugin-vue
    npm install @inertiajs/react react react-dom @vitejs/plugin-react
    npm install @inertiajs/svelte svelte @sveltejs/vite-plugin-svelte
  12. Style links during active requests with the data-loading attribute

    main
    When an Inertia link is making an active request, the library automatically adds a data-loading attribute to the link element. This attribute is removed once the request is complete. You can use this attribute in your CSS to provide visual feedback to users (e.g., showing a spinner or changing opacity) while a page transition is in progress.