Skip to main content

This django library allows you to add React components into your django templates.

Project description

Build Status PyPI version

Django-React-Templatetags

This django library allows you to add React (16+) components into your django templates.

Index

Requirements

  • Python 2.7 / Python 3.4+ / PyPy

  • Django 1.11+

Installation

Install the library with pip:

$ pip install django_react_templatetags

Quick Setup

Make sure django_react_templatetags is added to your INSTALLED_APPS.

INSTALLED_APPS = (
    # ...
    'django_react_templatetags',
)

You also need to add the react_context_processor into the context_middleware:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            'templates...',
        ],
        'APP_DIRS': True,
        'OPTIONS': {
            'debug': True,
            'context_processors': [
                ...
                'django_react_templatetags.context_processors.react_context_processor',
            ],
        },
    },
]

This should be enough to get started.

Usage

  1. Load the {% load react %}

  2. Insert the component anywhere in your template: {% react_render component="Component" props=my_data %}. This will create a dom placeholder.

  3. Put {% react_print %} in the end of your template. (This will output ReactDOM.render()/ReactDOM.hydrate() javascript).

  4. Make sure React and ReactDOM are included and that ReactDOM are exposed globally in js (ex window.ReactDOM = ReactDOM)

Settings

General

  • REACT_COMPONENT_PREFIX: Adds a prefix to your React.createElement include, if you want to keep your components outside the js glocal scope. (Default is empty == global scope).

    • Example using (REACT_COMPONENT_PREFIX="Cookie.") will look for components in a object named Cookie.

    • …Becomes: React.createElement(Cookie.MenuComponent, {})

  • REACT_RENDER_TAG_MANAGER: This is a advanced setting that lets you replace our tag parsing rules (ReactTagManager) with your own.

    • Example: "myapp.manager.MyReactTagManager"

SSR (Server Side Rendering)

  • REACT_RENDER_HOST: Which endpoint SSR requests should be posted at.

    • Example: http://localhost:7000/render-component/

    • The render host is a web service that accepts a post request and and renders the component to HTML. (This is what our Hastur service does)

  • REACT_RENDER_TIMEOUT: Timeout for SSR requests, in seconds.

  • REACT_RENDER_HEADERS: Override the default request headers sent to the SSR service. Default: {'Content-type': 'application/json', 'Accept': 'text/plain'}

    • Example: REACT_RENDER_HEADERS = {'Authorization': 'Basic 123'}

Examples

Single Component Example

This view…

from django.shortcuts import render

def menu_view(request):
    return render(request, 'myapp/index.html', {
        'menu_data': {
            'example': 1,
        },
    })

… and this template:

{% load react %}
<html>
    <head>...</head>

    <body>
        <nav>
            {% react_render component="Menu" props=menu_data %}
        </nav>
    </body>

    {% react_print %}
</html>

Will transform into this:

<html>
    <head>...</head>

    <body>
        <nav>
            <div id="Menu_405190d92bbc4d00b9e3376522982728"></div>
        </nav>
    </body>

    <script>
        ReactDOM.render(
            React.createElement(Menu, {"example": 1}),
            document.getElementById('Menu_405190d92bbc4d00b9e3376522982728')
        );
    </script>
</html>

Multi Component Example

You can also have multiple components in the same template

This view…

from django.shortcuts import render

def menu_view(request):
    return render(request, 'myapp/index.html', {
        'menu_data': {
            'example': 1,
        },
        'title_data': 'My title',
        'footer_data': {
            'credits': 'Copyright Company X'
        }
    })

… and this template:

{% load react %}
<html>
    <head>...</head>

    <body>
        <nav>
            {% react_render component="Menu" props=menu_data %}
            {% react_render component="Title" prop_title=title %}
            {% react_render component="Footer" props=footer_data %}
        </nav>
    </body>

    {% react_print %}
</html>

Will transform into this:

<html>
    <head>...</head>

    <body>
        <nav>
            <div id="Menu_405190d92bbc4d00b9e3376522982728"></div>
        </nav>
        <main>
            <div id="Title_405190d92bbc4d00b9e3376522982728"></div>
        </main>
        <footer>
            <div id="Footer_405190d92bbc4d00b9e3376522982728"></div>
        </footer>
    </body>

    <script>
        ReactDOM.render(
            React.createElement(Menu, {"example": 1}),
            document.getElementById('Menu_405190d92bbc4d00b9e3376522982728')
        );
        ReactDOM.render(
            React.createElement(Title, {"title": "My title"}),
            document.getElementById('Title_405190d92bbc4d00b9e3376522982728')
        );
        ReactDOM.render(
            React.createElement(Footer, {"credits": "Copyright Company X"}),
            document.getElementById('Footer_405190d92bbc4d00b9e3376522982728')
        );
    </script>
</html>

Example Application

Here is an example application of a fully React-rendered Django application with react-sass-starterkit. This was an example app for a Django-meetup talk, you might find the slides on Slideshare helpful.

Working with models

In this example, by adding RepresentationMixin as a mixin to the model, the templatetag will know how to generate the component data. You only need to pass the model instance to the react_render templatetag.

This model…

from django.db import models
from django_react_templatetags.mixins import RepresentationMixin

class Person(RepresentationMixin, models.Model):
    first_name = models.CharField(max_length=255)
    last_name = models.CharField(max_length=255)

    def to_react_representation(self, context={}):
        return {
            'first_name': self.first_name,
            'last_name': self.last_name,
        }

…and this view

import myapp.models import Person

def person_view(request, pk):
    return render(request, 'myapp/index.html', {
        'menu_data': {
            'person': Person.objects.get(pk=pk),
        },
    })

…and this template:

{% load react %}
<html>
    <head>...</head>

    <body>
        <nav>
            {% react_render component="Menu" props=menu_data %}
        </nav>
    </body>

    {% react_print %}
</html>

…will transform into this:

...

<script>
    ReactDOM.render(
        React.createElement(Menu, {"first_name": "Tom", "last_name": "Waits"}),
        document.getElementById('Menu_405190d92bbc4d00b9e3376522982728')
    );
</script>

Server Side Rendering

This library supports SSR (Server Side Rendering) throught third-part library Hastur.

It works by posting component name and props to endpoint, that returns the html rendition. Payload example:

{
    "componentName": "MyComponent",
    "props": {
        "title": "my props title",
        "anyProp": "another prop"
    },
    "static": false
}

REACT_RENDER_HOST needs to be defined to enable communication with service.

FAQ

How do I override the markup generated by react_print?

Simple! Just override the template react_print.html

This library only contains templatetags, where is the react js library?

This library only covers the template parts (that is: placeholder and js render).

I dont like the autogenerated element id, can I supply my own?

Sure! Just add the param identifier="yourid" in react_render.

Example:

{% react_render component="Component" identifier="yourid" %}

…will print

<div id="yourid"></div>

How do I pass individual props?

Add your props as arguments prefixed with prop_* to your {% react_render ... %}.

Example:

{% react_render component="Component" prop_country="Sweden" prop_city="Stockholm" %}

…will give the component this payload:

React.createElement(Component, {"country": "Sweden", "city": "Stockholm"}),

How do I apply my own css class to the autogenerated element?

Add class="yourclassname" to your {% react_render ... %}.

Example:

{% react_render component="Component" class="yourclassname" %}

…will print

<div id="Component_405190d92bbc4d00b9e3376522982728" class="yourclassname"></div>

I want to pass the component name as a variable, is that possible?

Yes! Just remove the string declaration and reference a variable in your {% react_render ... %}, the same way you do with props.

Example:

This view

render(request, 'myapp/index.html', {
    'component_name': 'MegaMenu',
})

…and this template

{% react_render component=component_name %}

…will print:

<div id="Component_405190d92bbc4d00b9e3376522982728" class="yourclassname"></div>
React.createElement(MegaMenu),

Tests

This library include tests, just run python runtests.py

You can also run separate test cases: runtests.py tests.test_filters.ReactIncludeComponentTest

Contributing

Want to contribute? Awesome. Just send a pull request.

License

Django-React-Templatetags is released under the MIT License.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_react_templatetags-5.2.0.tar.gz (13.8 kB view hashes)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page