Skip to content
This repository has been archived by the owner on Jan 25, 2020. It is now read-only.

jsbeckr/inertia-django

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

8 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Inertia.js Django Adapter

Warning: This project is in a very early stage and depends on another early stage library and its frontend adapters called Inertia.js.

Requirements

This package is meant to be used in a Django application and it uses django-rest-framework's serializers.

$ pipenv install django djangorestframework django-webpack-loader

Installation

There is still a few too many manual steps involved using inertia-django. I'm looking for ways (and people to help) to make the initial setup more smooth.

Install the inertia-django package from PyPI:

$ pipenv install inertia-django

Django app template

The easiest way to get started is with the inertia-django-boilerpate.

Webpack πŸ“¦

INFO: For now it might be the easiest to take a look or clone the example repository.

You have to use webpack for the Dynamic Imports Feature. The following config is borrowed from the Django Inertia.js Example. It uses a few plugins that are not necessary like PurgeCSS, Tailwind, MiniCSSExtract, etc. But the important ones are:

webpack.config.js:

const path = require("path");
const BundleTracker = require('webpack-bundle-tracker');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');

const glob = require("glob-all");
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const PurgecssPlugin = require("purgecss-webpack-plugin");

class TailwindExtractor {
  static extract(content) {
    return content.match(/[A-Za-z0-9-_:\/]+/g) || [];
  }
}

module.exports = {
  mode: 'development',
  devtool: 'inline-source-map',
  // TODO: adjust the entry points to your project
  entry: ["./core/assets/js/index.js", "./core/assets/css/index.postcss"],
  output: {
    publicPath: "/static/bundles/",
    filename: "[name]-[hash].js",
    chunkFilename: '[name]-[hash].js',
    path: path.resolve('./bundles/'),
  },

  plugins: [
    new BundleTracker({ filename: './webpack-stats.json' }),
    new VueLoaderPlugin(),
    new CleanWebpackPlugin(),
    new MiniCssExtractPlugin({
      filename: "[name]-[hash].css"
    }),
    new PurgecssPlugin({
      paths: glob.sync([
        // TODO: adjust the directories to your project
        path.join(__dirname, "core/assets/js/**/*.vue"),
        path.join(__dirname, "core/templates/index.html")
      ]),
      extractors: [
        {
          extractor: TailwindExtractor,
          extensions: ["html", "js", "vue"]
        }
      ]
    })
  ],

  module: {
    rules: [
      {
        test: /\.m?js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              '@babel/preset-env'
            ],
            plugins: ["@babel/plugin-syntax-dynamic-import"]
          }
        }
      },
      {
        test: /\.vue$/,
        use: 'vue-loader'
      },
      {
        test: /\.postcss$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
          },
          { loader: 'css-loader', options: { importLoaders: 1 } },
          'postcss-loader',
        
        ]
      }
    ]
  },

  resolve: {
    extensions: ['.js', '.vue'],
    alias: {
      'vue$': 'vue/dist/vue.runtime.js',
      // TODO: adjust or remove, it's a convenient way to import js files in your components
      '@': path.resolve('core/assets/js'),
    }
  },
}

Usage

render_inertia function

The easiest way to render a Vue component with inertia-django is to use the render_inertia function. Note: You have to have an Index.vue component in your project.

from inertia import render_inertia

def index(request):
    # for function views just use the render_inertia function
    return render_inertia(request, 'Index', props={'title': 'My inertia-django page'}, template_name='index.html')

This would be a bit much to write everytime so you can omit the template_name and set it in settings.py:

INERTIA_TEMPLATE = 'index.html'

After that you just have to call:

from inertia import render_inertia

def index(request):
    # for function views just use the render_inertia function
    return render_inertia(request, 'Index', props={'title': 'My inertia-django page'})

InertiaListView

inertia-django ships with a crude implementations of the generic ListView:

views.py:

class Index(InertiaListView):
    # Inertia supports List and DetailViews right now
    model = Contact
    serializer_class = ContactSerializer
    component_name = "Index"

Index.vue

<template>
  <Layout>
    <h2 class="mb-4">Contacts</h2>
    <p>User: {{shared.user.username}}</p>
    <ul>
      <li :key="contact.id" v-for="contact in contact_list">
        <inertia-link :href="'/contact/' + contact.id">
          {{contact.name}}
        </inertia-link>
      </li>
    </ul>
  </Layout>
</template>

<script>
import { InertiaLink } from "inertia-vue";
import Layout from "@/Components/Layout";

export default {
  props: ["contact_list", "shared"],
  components: { Layout, InertiaLink }
};
</script>

InertiaDetailView

inertia-django ships with a crude implementations of the generic DetailView:

views.py:

class ContactView(InertiaDetailView):
    model = Contact
    serializer_class = ContactSerializer
    component_name = "Contact"
    props = {"test": True} # you can inject any props you want

Contact.vue:

<template>
  <Layout>
    <inertia-link href="/">Home</inertia-link>
    <h2 class="mb-4">{{contact.name}}, {{contact.first_name}}</h2>
    <p>Age: {{contact.age}}</p>
    <p>Test: {{test}}</p>
  </Layout>
</template>

<script>
import { InertiaLink } from "inertia-vue";
import Layout from "@/Components/Layout";

export default {
  props: ['contact', 'test'],
  components: { Layout, InertiaLink }
};
</script>

inertia.share function

If you want to have some basic props that are always injected, you can share them between Components:

I had to declare the UserSerializer in apps.py so that it is available at startup. If somebody has a better idea feel free to create an issue.

e.g. apps.py:

from django.apps import AppConfig
from django.contrib.auth import get_user, get_user_model
from rest_framework import serializers
from inertia import share


def current_user(request):
    class UserSerializer(serializers.ModelSerializer):

        class Meta:
            model = get_user_model()
            fields = ["username", "email"]

    return UserSerializer(get_user(request)).data


class CoreConfig(AppConfig):
    name = 'core'

    def ready(self):
        share('title', 'Django Inertia.js Example 🀘')
        share('user', current_user)

As you might have recognized current_user is a function. While rendering inertia-django checks if a shared property is callable and if it is, it will call that function with the current request.

Example

Take a look at this repository for an example of how to use this package.

About

The Django adapter for Inertia.js

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published