Django + Next.js integration

Related tags

Djangodjango-nextjs
Overview

Django Next.js

Django + Next.js integration

From a comment on StackOverflow:

Run 2 ports on the same server. One for django (public facing) and one for Next.js (internal). Let django handle all web requests. For each request, query Next.js from django view to get HTML response. Return that exact HTML response from django view.

Installation

  • Install the latest version from PyPI.

    pip install django-nextjs
  • Add django_nextjs to INSTALLED_APPS.

  • In Development Environment:

    • If you're using django channels, add NextJSProxyHttpConsumer and NextJSProxyWebsocketConsumer to asgi.py:

      import os
      
      from django.core.asgi import get_asgi_application
      from django.urls import re_path
      
      os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings")
      django_asgi_app = get_asgi_application()
      
      from channels.auth import AuthMiddlewareStack
      from channels.routing import ProtocolTypeRouter, URLRouter
      from django_nextjs.proxy import NextJSProxyHttpConsumer, NextJSProxyWebsocketConsumer
      
      from django.conf import settings
      
      http_routes = [...]
      websocket_routers = [...]
      if settings.DEBUG:
          http_routes.insert(0, re_path(r"^(?:_next|__next|next).*", NextJSProxyHttpConsumer.as_asgi()))
          websocket_routers.insert(0, path("_next/webpack-hmr", NextJSProxyWebsocketConsumer.as_asgi()))
      
      
      application = ProtocolTypeRouter(
          {
              # Django's ASGI application to handle traditional HTTP and websocket requests.
              "http": URLRouter(http_routes),
              "websocket": AuthMiddlewareStack(URLRouter(websocket_routers)),
              # ...
          }
      )
    • Otherwise, add the following to the beginning of urls.py:

      path("", include("django_nextjs.urls"))
  • In Production:

    • Use a reverse proxy like nginx:

      URL Action
      /_next/static/... Serve NEXTJS_PATH/.next/static directory
      /_next/... Proxy to http://localhost:3000
      /next/... Serve NEXTJS_PATH/public/next directory

      Pass x-real-ip header when proxying /_next/:

      location /_next/ {
          proxy_set_header  x-real-ip $remote_addr;
          proxy_pass  http://127.0.0.1:3000;
      }
      

Usage

Start Next.js server:

# Development:
$ npm run dev

# Production:
$ npm run build
$ npm run start

Develop your pages in Next.js. Write a django URL and view for each page like this:

# If you're using django channels
from django.http import HttpResponse
from django_nextjs.render import render_nextjs_page_async

async def jobs(request):
    return await render_nextjs_page_async(request)
# If you're not using django channels
from django.http import HttpResponse
from django_nextjs.render import render_nextjs_page_sync

def jobs(request):
    return render_nextjs_page_sync(request)

Customizing Document

If you want to customize the HTML document (e.g. add header or footer), read this section.

You need to customize Next's document:

  • Add id="__django_nextjs_body" as the first attribute of <body> element.
  • Add <div id="__django_nextjs_body_begin" /> as the first element inside <body>.
  • Add <div id="__django_nextjs_body_end" /> as the last element inside <body>.
import Document, { Html, Head, Main, NextScript } from "next/document";

// https://nextjs.org/docs/advanced-features/custom-document
class MyDocument extends Document {
  render() {
    return (
      <Html>
        <Head />
        <body id="__django_nextjs_body" dir="rtl">
          <div id="__django_nextjs_body_begin" />
          <Main />
          <NextScript />
          <div id="__django_nextjs_body_end" />
        </body>
      </Html>
    );
  }
}

export default MyDocument;

Write a django template that extends django_nextjs/document_base.html:

{% extends "django_nextjs/document_base.html" %}


{% block head %}
  ... the content you want to add to the beginning of <head> tag ...
  {{ block.super }}
  ... the content you want to add to the end of <head> tag ...
{% endblock %}


{% block body %}
  ... the content you want to add to the beginning of <body> tag ...
  {{ block.super }}
  ... the content you want to add to the end of <body> tag ...
{% endblock %}

Pass the template name to render_nextjs_page_async or render_nextjs_page_sync:

# If you're using django channels
async def jobs(request):
    return await render_nextjs_page_async(request, "path/to/template.html")
# If you're not using django channels
def jobs(request):
    return render_nextjs_page_sync(request, "path/to/template.html")

Notes

  • If you want to add a file to public directory of Next.js, that file should be in public/next subdirectory to work correctly.
  • If you're using django channels, make sure all your middlewares are async-capable.

Settings

Default settings:

    NEXTJS_SETTINGS = {
        "nextjs_server_url": "http://127.0.0.1:3000",
    }

nextjs_server_url

The URL of Next.js server (started by npm run dev or npm run start)

Development

  • Install development dependencies in your virtualenv with pip install -e '.[dev]'
  • Install pre-commit hooks using pre-commit install.

References

Comments
  • _next/webpack-hmr' failed: / Too many redirects

    _next/webpack-hmr' failed: / Too many redirects

    Hello,

    i've try to install the package like described in the readme.

    Environment:

    • Next.js v12.2.4
    • Django 4.0.6

    Everything was installed successfully but i have several errors:

    First of all on index js i get the error: WebSocket connection to 'ws://127.0.0.1:8000/_next/webpack-hmr' failed: Bildschirmfoto 2022-08-09 um 19 40 11

    But i can see the nextjs index.

    Then i want to try to change the route to /test

    I described a view and parsed it to the url. If i call the url i got the error: too many redirects and the page wouldn't load:

    Bildschirmfoto 2022-08-09 um 19 43 54 Bildschirmfoto 2022-08-09 um 19 43 49

    Here my Settings.py:

    from pathlib import Path
    
    BASE_DIR = Path(__file__).resolve().parent.parent
    
    SECRET_KEY = 'django-insecure-%2spqobsw&i$k(n(%(siwd#fxzh^h%wqk5nc3nx0_$upu8r5!q'
    
    DEBUG = True
    
    ALLOWED_HOSTS = []
    
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        "django_nextjs",
    ]
    
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]
    
    ROOT_URLCONF = 'empire_next.urls'
    
    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [],
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
            },
        },
    ]
    
    WSGI_APPLICATION = 'empire_next.wsgi.application'
    
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': BASE_DIR / 'db.sqlite3',
        }
    }
    
    
    AUTH_PASSWORD_VALIDATORS = [
        {
            'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
        },
    ]
    
    
    LANGUAGE_CODE = 'en-us'
    
    TIME_ZONE = 'UTC'
    
    USE_I18N = True
    
    USE_TZ = True
    
    
    STATIC_URL = 'static/'
    
    
    
    DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
    

    views.py

    from django.shortcuts import render
    
    # Create your views here.
    
    from django_nextjs.render import render_nextjs_page_sync
    
    
    def index(request):
        return render_nextjs_page_sync(request)
    
    
    def test(request):
        return render_nextjs_page_sync(request)
    

    urls.py

    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path("", include("backend.urls")),
        path("", include("django_nextjs.urls")),
    ]
    

    backend.urly.py:

    from django.urls import path
    from .views import index
    urlpatterns = [
        path("", index, name="index"),
        path("test/", index, name="test"),
    ]
    

    any solution for this?

    opened by Amplitude88 9
  • for next.js v12 thru Django channels, 'admin/' doesn't work

    for next.js v12 thru Django channels, 'admin/' doesn't work

    after changing to channels with asgi.py, 'admin' listed in urls.py can not accessed correctly. any guidance about how to handle middleware like this? Thanks,

    my urls.py is:

    from django.contrib import admin
    from django.urls import include, path, re_path
    from django.views.generic.base import RedirectView
    # from .views import jobs
    
    # favicon_view = RedirectView.as_view(url='static/vercel.svg', permanent=True)
    
    urlpatterns = [
        # path('', jobs),
        path('admin/', admin.site.urls),
        re_path(r'^vercel\.svg$', RedirectView.as_view(url='static/vercel.svg')),
        path('favicon.ico', RedirectView.as_view(url='static/favicon.ico')),  
    ]
    

    all these 3 paths are not working if channels and django-nextjs enabled in INSTALLED_APPS in settings.py.

    opened by crossz 6
  • Issue when running nextjs

    Issue when running nextjs

    hey my nextjs version is:

    @next/[email protected]
    ├─ @next/[email protected]
    ├─ @next/[email protected]
    ├─ @next/[email protected]
    ├─ @next/[email protected]
    ├─ @next/[email protected]
    ├─ @next/[email protected]
    ├─ @next/[email protected]
    ├─ @next/[email protected]
    ├─ @next/[email protected]
    ├─ @next/[email protected]
    ├─ @next/[email protected]
    ├─ @next/[email protected]
    ├─ @next/[email protected]
    ├─ [email protected]
    │  ├─ @next/[email protected]
    │  ├─ resolve@^2.0.0-next.3
    │  ├─ [email protected]
    ├─ [email protected]
    │  ├─ @next/[email protected]
    │  ├─ @next/[email protected]
    │  ├─ @next/[email protected]
    │  ├─ @next/[email protected]
    │  ├─ @next/[email protected]
    │  ├─ @next/[email protected]
    │  ├─ @next/[email protected]
    │  ├─ @next/[email protected]
    │  ├─ @next/[email protected]
    │  ├─ @next/[email protected]
    │  ├─ @next/[email protected]
    │  ├─ @next/s[email protected]
    │  ├─ @next/[email protected]
    

    I am getting 'WebSocket connection to 'ws://localhost:8000/_next/webpack-hmr' failed: ' screenshot attached Screenshot at May 26 22-07-27

    opened by aashishg 6
  • Issues when running the Django server in production mode

    Issues when running the Django server in production mode

    Hi,

    If the Django server is set to run with debug=False, then all the requests will pass through the render_nextjs_page_sync, according to this statement in urls.py:

    if settings.DEBUG:
        # only in dev environment
        urlpatterns.append(re_path(r"^(?:_next|__nextjs|next).*$", NextJSProxyView.as_view()))
    

    The problem is that all the .js bundles requests will have their content-type property set to text/html, as this is happening for each request that passes through this view:

    from django_nextjs.render import render_nextjs_page_sync
    
    def index(request):
        return render_nextjs_page_sync(request)
    

    Should the content-type be manually computed and then specified as an argument to the render_nextjs_page_sync method? I don't see other way around it.

    Thank you!

    opened by ISilviu 2
  • Add redirect support

    Add redirect support

    Currently, redirects received from the NextJS server are not supported. More specifically, I'm referring to this kind of redirects:

    image

    I have roughly added support for 308 codes, yet the implementation is not tested nor does it feel complete. Could you please guide me on how to complete this implementation?

    opened by ISilviu 2
  • Pass allow_redirects parameter to render function

    Pass allow_redirects parameter to render function

    Hello, I am a Korean django developer.

    I work for a company called Buildblock and I want to change the frontend technology stack from django template to nextjs. However, django couldn't recognize the static file built in nextjs and ended up using django-nextjs.

    However, redirects are required for translation on our website, but django-nextjs redirects were rejected because allow_redirects was False. So this error occurred.

    Therefore, it is suggested to add allow_redirects as a parameter to the render_nextjs_page_sync function. We confirmed that this change would give us the desired behavior.

    I look forward to a good answer. thank you

    opened by SeokEunJu 1
  • for next.js v12 vercel.svg can not loaded

    for next.js v12 vercel.svg can not loaded

    After changing to Django channels and asgi.py in order to make websocket work, I tried all static files deployment configuration for Django 4, nothing works for correct loading vercel.svg. Please provide some guidance about this.

    opened by crossz 1
  • Cannot visit another endpoint

    Cannot visit another endpoint

    I followed the steps from this tutorial. I added the created a new app called frontend and added the following codes:

    # myproject/urls.py
    from django.urls import include, path
    urlpatterns = [
        # ...
        path("", include("frontend.urls")),
        path("", include("django_nextjs.urls")),
    ]
    
    # frontend/views.py
    from django_nextjs.render import render_nextjs_page_sync
    def index(request):
        return render_nextjs_page_sync(request)
    
    # frontend/urls.py
    from django.urls import path
    from .views import index
    urlpatterns = [
        path("", index, name="index"),
    ]
    

    I can now see the homepage (situated at "localhost:8000/" route) But I can't visit any other routes like "http://localhost:8000/create" which I can visit from my nextjs server "http://localhost:3000/create".

    I tried adding a new route in frontend.urls.py like this

    from django.urls import path
    from .views import index
    
    urlpatterns = [
        path("", index, name="index"),
        path("create/", index, name="index"),
    ]
    

    but I kept getting too many redirects. Can someone show me the correct way to do this or is it even necessary to add endpoints manually?

    opened by sugamkarki 1
  • Use ** syntax

    Use ** syntax

    I'm unable to use the library on a Python 3.8.5 environment, it complaints about the following issue:

    unsupported operand type(s) for |: 'dict' and 'dict'
    

    Couldn't the library just use the ** syntax, which is supported starting from Python 3.5?

    opened by ISilviu 1
  • Want to pass allow_redirects parameter to render function

    Want to pass allow_redirects parameter to render function

    While using django-nextjs, there is a situation where need to set allow_redirects to True, so I suggest adding the allow_redirects field as a parameter to functions such as render_nextjs_page_sync.

    Please check here for details.

    thank you.

    opened by SeokEunJu 0
  • Incorrect Type Annotations

    Incorrect Type Annotations

    Some type annotations are incorrect, e.g. the return type of render_nextjs_page_sync and render_nextjs_page_async.

    https://github.com/QueraTeam/django-nextjs/blob/d29b04e8064afbff2496430e7b3bbda81a78ee16/django_nextjs/render.py#L62

    https://github.com/QueraTeam/django-nextjs/blob/d29b04e8064afbff2496430e7b3bbda81a78ee16/django_nextjs/render.py#L103

    https://github.com/QueraTeam/django-nextjs/blob/d29b04e8064afbff2496430e7b3bbda81a78ee16/django_nextjs/render.py#L112

    https://github.com/QueraTeam/django-nextjs/blob/d29b04e8064afbff2496430e7b3bbda81a78ee16/django_nextjs/render.py#L154

    opened by mjnaderi 0
Releases(v2.2.1)
Owner
Quera
Practice Programming, Compete, Find Tech Jobs!
Quera
Exploit Discord's cache system to remote upload payloads on Discord users machines

Exploit Discord's cache system to hide payloads PoC Remote upload embedded payload from image using EOF to Discord users machines through cache. Depen

cs 169 Dec 20, 2022
Template for Django Project Using Docker

You want a Django project who use Docker and Docker-compose for Development and for Production ? It's for you !

1 Dec 17, 2021
Django REST Client API

Django REST Client API Client data provider API.

Ulysses Monteiro 1 Nov 08, 2021
A starter template for building a backend with Django and django-rest-framework using docker with PostgreSQL as the primary DB.

Django-Rest-Template! This is a basic starter template for a backend project with Django as the server and PostgreSQL as the database. About the templ

Akshat Sharma 11 Dec 06, 2022
ProjectManagementWebsite - Project management website for CMSC495 built using the Django stack

ProjectManagementWebsite A minimal project management website for CMSC495 built

Justin 1 May 23, 2022
Full featured redis cache backend for Django.

Redis cache backend for Django This is a Jazzband project. By contributing you agree to abide by the Contributor Code of Conduct and follow the guidel

Jazzband 2.5k Jan 03, 2023
Add a help desk or knowledge base to your Django project with only a few lines of boilerplate code.

This project is no longer maintained. If you are interested in taking over the project, email Zapier 487 Dec 06, 2022

Realworld - Realworld using Django and HTMX

Realworld - Realworld using Django and HTMX

Dan Jacob 53 Jan 05, 2023
Send push notifications to mobile devices through GCM or APNS in Django.

django-push-notifications A minimal Django app that implements Device models that can send messages through APNS, FCM/GCM and WNS. The app implements

Jazzband 2k Dec 26, 2022
Imparare Django ricreando un sito facsimile a quello Flask

SitoPBG-Django Imparare Django ricreando un sito facsimile a quello Flask Note di utilizzo Necessita la valorizzazione delle seguenti variabili di amb

Mario Nardi 1 Dec 08, 2021
Twitter Bootstrap for Django Form

Django bootstrap form Twitter Bootstrap for Django Form. A simple Django template tag to work with Bootstrap Installation Install django-bootstrap-for

tzangms 557 Oct 19, 2022
Comparing Database performance with Django ORM

Comparing Database performance with Django ORM Postgresql MySQL MariaDB SQLite Comparing database operation performance using django ORM. PostgreSQL v

Sarath ak 21 Nov 14, 2022
Probably the best abstract model / admin for your tree based stuff.

django-treenode Probably the best abstract model / admin for your tree based stuff. Features Fast - get ancestors, children, descendants, parent, root

Fabio Caccamo 360 Jan 05, 2023
Pipeline is an asset packaging library for Django.

Pipeline Pipeline is an asset packaging library for Django, providing both CSS and JavaScript concatenation and compression, built-in JavaScript templ

Jazzband 1.4k Jan 03, 2023
The little ASGI framework that shines. 🌟

✨ The little ASGI framework that shines. ✨ Documentation: https://www.starlette.io/ Community: https://discuss.encode.io/c/starlette Starlette Starlet

Encode 7.7k Dec 31, 2022
✋ Auto logout a user after specific time in Django

django-auto-logout Auto logout a user after specific time in Django. Works with Python 🐍 ≥ 3.7, Django 🌐 ≥ 3.0. ✔️ Installation pip install django-a

Georgy Bazhukov 21 Dec 26, 2022
Django-pwned - A collection of django password validators

Django Pwned A collection of django password validators. Compatibility Python: 3

Quera 22 Jun 27, 2022
The uncompromising Python code formatter

The Uncompromising Code Formatter “Any color you like.” Black is the uncompromising Python code formatter. By using it, you agree to cede control over

Python Software Foundation 30.7k Jan 03, 2023
Updates redisearch instance with igdb data used for kimosabe

igdb-pdt Update RediSearch with IGDB games data in the following Format: { "game_slug": { "name": "game_name", "cover": "igdb_coverart_url",

6rotoms 0 Jul 30, 2021
An automatic django's update checker and MS teams notifier

Django Update Checker This is small script for checking any new updates/bugfixes/security fixes released in django News & Events and sending correspon

prinzpiuz 4 Sep 26, 2022