Next.js + Django集成
项目描述
Django Next.js
Next.js集成到Django项目。
因此,您想在项目中同时使用Django和Next.js。有两种情况
-
您正在启动一个新项目,并且想使用Django作为后端,Next.js作为前端。Django只处理API请求。所有前端代码都位于Next.js中,您不需要编写任何Django模板。
在这种情况下,您不需要这个包(尽管可以使用它)。您只需启动Django和Next.js服务器,并将您的公共Web服务器指向Next.js。
-
您需要同时使用Django模板和Next.js,并且这些页面应能够轻松链接。也许您有一个现有的Django项目,其中包含由Django模板渲染的页面,并且想添加一些新的Next.js页面。或者,您想将前端迁移到Next.js,但由于项目较大,您需要逐步进行。
在这种情况下,这个包是为您准备的!
它是如何工作的?
来自StackOverflow上的评论
在同一服务器上运行2个端口。一个用于Django(面向公众)和一个用于Next.js(内部)。让Django处理所有Web请求。对于每个请求,从Django视图查询Next.js以获取HTML响应。从Django视图返回确切的HTML响应。
安装
-
从PyPI安装最新版本。
pip install django-nextjs
-
将
django_nextjs.apps.DjangoNextJSConfig
添加到INSTALLED_APPS
。 -
根据您的环境设置Next.js URL。
设置Next.js URL(开发环境)
如果在开发期间通过ASGI提供服务,请使用Django Channels并将NextJSProxyHttpConsumer
和NextJSProxyWebsocketConsumer
添加到asgi.py
,如下例所示。
注意:我们建议使用ASGI和Django Channels,因为这是Nextjs 12+中快速刷新(热模块替换)正常工作的要求。
import os
from django.core.asgi import get_asgi_application
from django.urls import re_path, 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
# put your custom routes here if you need
http_routes = [re_path(r"", django_asgi_app)]
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)),
# ...
}
)
否则(如果在开发期间通过WSGI提供服务),将以下内容添加到urls.py
的开头
path("", include("django_nextjs.urls"))
警告:如果您在ASGI下提供服务,请不要将其添加到您的urls.py
中。这可能会导致死锁。
设置Next.js URL(生产环境)
在生产中,使用Nginx或Caddy等反向代理。
URL | 动作 |
---|---|
/_next/static/... |
提供NEXTJS_PATH/.next/static 目录 |
/_next/... |
代理到http://localhost:3000 |
/next/... |
提供NEXTJS_PATH/public/next 目录 |
Ngxin配置示例
location /_next/static/ {
alias NEXTJS_PATH/.next/static/;
expires max;
add_header Cache-Control "public";
}
location /_next/ {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /next/ {
alias NEXTJS_PATH/public/next/;
expires max;
add_header Cache-Control "public";
}
用法
启动Next.js服务器
# Development:
$ npm run dev
# Production:
$ npm run build
$ npm run start
首先在Next.js中开发您的页面,然后为每个Next.js页面定义一个Django URL。以下是如何操作的示例
from django_nextjs.views import nextjs_page
urlpatterns = [
path("/nextjs/page", nextjs_page(), name="nextjs_page"),
]
尽管不建议这样做,但有时您可能需要在Django中显示Next.js页面之前添加一些自定义步骤。然而,我们建议将此逻辑移至Next.js以确保即使在客户端重定向期间也适用。如果您发现自己处于这种情况,可以像下面那样为每个页面创建一个异步视图
from django_nextjs.render import render_nextjs_page
async def jobs(request):
# Your custom logic
return await render_nextjs_page(request)
自定义HTML响应
您可以在Django代码中修改Next.js返回的HTML代码。
避免重复编写导航栏和页脚的代码是此功能的常见用例,如果您同时使用Next.js和Django模板。否则,您将不得不编写并维护两个版本的导航栏和页脚(Django模板版本和Next.js版本)。但是,您可以简单地创建一个Django模板用于导航栏,并在Next.js返回的<body>
标签的开头插入其代码。
要启用此功能,您需要自定义Next.js中的文档和根布局,并做出以下调整
- 将
id="__django_nextjs_body"
作为<body>
元素的第一个属性。 - 将
<div id="__django_nextjs_body_begin" />
作为<body>
中的第一个元素。 - 将
<div id="__django_nextjs_body_end" />
作为<body>
中的最后一个元素。
注意:目前HTML自定义功能不与app路由(Next.js 13+)一起工作。
阅读此文档并自定义您的Next.js文档
// pages/_document.jsx (or .tsx)
...
<body id="__django_nextjs_body">
<div id="__django_nextjs_body_begin" />
<Main />
<NextScript />
<div id="__django_nextjs_body_end" />
</body>
...
编写一个扩展django_nextjs/document_base.html
的Django模板
{% extends "django_nextjs/document_base.html" %}
{% block head %}
<!-- ... the content you want to place at the beginning of "head" tag ... -->
{{ block.super }}
<!-- ... the content you want to place at the end of "head" tag ... -->
{% endblock %}
{% block body %}
... the content you want to place at the beginning of "body" tag ...
... e.g. include the navbar template ...
{{ block.super }}
... the content you want to place at the end of "body" tag ...
... e.g. include the footer template ...
{% endblock %}
将模板名称传递给nextjs_page
或render_nextjs_page
from django_nextjs.render import render_nextjs_page
from django_nextjs.views import nextjs_page
async def jobs(request):
return await render_nextjs_page(request, template_name="path/to/template.html")
urlpatterns = [
path("/nextjs/page", nextjs_page(template_name="path/to/template.html"), name="nextjs_page"),
path("/jobs", jobs, name="jobs_page")
]
注意
- 如果您要将文件添加到Next.js的
public
目录,则该文件应在public/next
子目录中才能正常工作。 - 如果您使用Django channels,请确保所有中间件都是异步兼容的。
- 为了避免“过多重定向”错误,您可能需要在Django项目的
settings.py
中添加APPEND_SLASH = False
。另外,请不要在urls.py
中的nextjs路径末尾添加/
。 - 此包不提供从Django传递数据到Next.js的解决方案。应继续使用Django Rest Framework、GraphQL或类似解决方案。
- 此包不会运行Next.js服务器。您需要自行运行它。
设置
默认设置
NEXTJS_SETTINGS = {
"nextjs_server_url": "http://127.0.0.1:3000",
"ensure_csrf_token": True,
}
nextjs_server_url
Next.js服务器地址(由npm run dev
或npm run start
启动)
ensure_csrf_token
如果用户没有CSRF令牌,则通过调用Django的django.middleware.csrf.get_token
确保生成一个令牌并将其包含在发送到Next.js服务器的初始请求中。如果安装了django.middleware.csrf.CsrfViewMiddleware
,则初始响应将包括一个Set-Cookie
头,以在客户端持久化CSRF令牌值。默认情况下启用此行为。
何时需要ensure_csrf_token
?
您可能需要在Next.js的getServerSideProps
中发出GraphQL POST请求以获取数据。如果这是用户的第一个请求,则不会有CSRF cookie,导致请求失败,因为GraphQL即使在数据获取时也使用POST。但是,只要getServerSideProps
函数是副作用免费的(即,它们不使用HTTP不安全的方法或GraphQL突变),从安全角度来看应该没问题。更多信息请参阅这里。
开发
- 使用
pip install -e '.[dev]'
在您的虚拟环境中安装开发依赖项。 - 使用
pre-commit install
安装pre-commit钩子。
参考
许可证
MIT
项目详情
下载文件
下载您平台上的文件。如果您不确定选择哪个,请了解有关安装包的更多信息。