反应路由和Django URL冲突



我使用reactjs作为前端,而django作为后端。React路由器用于路由。当我刷新React路由器路由的页面时,我会得到Django 404 Page Not Found error。如果我刷新主页,我不会遇到任何错误,因为Django模板也使用其URL呈现主页。

我必须在WebPack中配置它吗?我的项目结构是我已经分离了Django和ReactJ。我创建了一个文件夹,作为reactjs文件所在的前端。

update

主页模板具有诸如Addrestaurant之类的路线的所有链接。

我的webpack.config文件

const path = require("path");
if(!process.env.NODE_ENV) {
    process.env.NODE_ENV = 'development';
}
module.exports = {
  entry: [
    './src/index.js'
  ],
  output: {
    path: path.join("../app/static/build/", "js"),
    filename: "app.js",
    publicPath: "../app/static/build/"
  },
  devtoo: 'source-map',
  debug: true,
  module: {
    loaders: [{
      exclude: /node_modules/,
      loader: 'babel',
      query: {
        presets: ['react', 'es2015', 'stage-1']
      }
    },
    {test: /.(jpe?g|png|gif|svg)$/i, loader: "url-loader?name=images/[name].[ext]"},
    ]
  },
  resolve: {
    extensions: ['', '.js', '.jsx']
  },
  devServer: {
    historyApiFallback: true,
    contentBase: './'
  }
};

urls.py

urlpatterns = [
    url(r'^', views.home, name="homePage"),
    url(r'^(?:.*)/?$', views.home),
]

home.html

{% extends 'base.html' %}
{% block title %} Foodie | Homepage {% endblock title%}
{% block content %}
  <div class="homepage">
  </div>
{% endblock %}
{% block js %}
  {{ block.super }}
  <script type="text/javascript">
  var data = {
         isUserAuthenticated:{% if request.user.is_authenticated %}true{% else %}false{% endif %}
    };
    console.log('data',data);
    $(function() {
      app.showHomePage(".homepage",data);
    });
  </script>
{% endblock %}

index.js

window.app = {
      showHomePage: function(id,data){
          render(
            <Provider store={createStoreWithMiddleware(reducers)}>
                <Router>
                 <App />
                </Router>
            </Provider>, document.querySelector(id)
          );
      },
}

横幅是应用程序组件的子部分

const Banner = (props) => (
   <div className="navbar-container">
        <div className="ui container">
            <div className="ui large secondary menu">
                <a className="toc item">
                    <i className="sidebar icon"></i>
                </a>
                <div className="item logo">
                    <div className="ui logo shape">
                        <div className="sides">
                            <div className="active ui side">
                                Foodie
                            </div>
                        </div>
                    </div>
                </div>
                <Link to="/restaurant" className="active item tab">Home</Link>
                <Link to='/addrestaurant' className='item tab'>Add Restaurant</Link>
                <Link to="/products" className="item tab">Products</Link>
                <div className="right item">
                    <a href="" id="bookingInfoButton" className="ui white inverted button">Booking</a>
                </div>
            </div>
        </div>
      </div>
);
export default Banner;

问题可能是您尚未配置URL来处理React路由器中定义的路由。在您的django urls.py中,您应该使用catch all catch将所有URL匹配到索引模板

urlpatterns += [
    # match the root
    url(r'^$', base_view),
    # match all other pages
    url(r'^(?:.*)/?$', base_view),
]

base_view将是一个视图函数,它呈现一个模板,其中包括您的捆绑应用程序。

如果任何人都有同样的问题,在Django 2.0中,请按照'Kevin Martin Jose'答案,而是用 url 替换为 re_path

from django.urls import path, re_path
urlpatterns = [
    path('login/', LoginView.as_view(), name='login'),
    path('logout/', LogoutView.as_view()),
    path('/', login_required(TemplateView.as_view(template_name="app.html"), 
    login_url='login')),
    re_path(r'^(?:.*)/?$', login_required(TemplateView.as_view(template_name="app.html"), 
    login_url='login')),
]

以防万一有人想知道,我有一个确切的问题,保罗的答案解决了。添加答案而不是评论仅是因为我不允许我在注释中格式化代码片段。我最终使用了Django的新path()和我的urls.py中的旧urls()的混合物:

urlpatterns = [
    path('login/', LoginView.as_view(), name='login'),
    path('logout/', LogoutView.as_view()),
    path('/', login_required(TemplateView.as_view(template_name="app.html"), 
    login_url='login')),
    url(r'^(?:.*)/?$',    login_required(TemplateView.as_view(template_name="app.html"), 
    login_url='login')),
]

Django处理登录,注销和根/。React路由器处理其他所有内容

这是凯文·琼斯(Kevin Jones)和保罗(Paul)的答案启发的答案。我对正则遇到问题并托管REST API。如果我的前端应用程序在拨打API时没有附加斜线,则它将不匹配,并且会返回前端。这是因为DJANGO设置APPEND_SLASH=True要求它通过urlpatterns,并且在附加斜线并再次尝试之前就失败了一次。因此,这里有一条正则是从" API"或" Admin"开始的任何内容,否则将其发送到前端。

urlpatterns = [
path("admin/", admin.site.urls),
path("api/", include(router.urls)),  # from rest_framework
re_path('(^(?!(api|admin)).*$)',
    TemplateView.as_view(template_name="build/index.html")),
] 

这是一个解决方案,不会引起其他视图的覆盖,并且不需要您丢弃404处理程序。

缺点在于,这需要保留您的路线的最新列表,但这就是该文件的目的。

urls.py中:

from django.urls import re_path
from myapp import views
# This wrapper turns your list into a regex URL matcher
react_views_regex = r'/|b'.join([
    # List all your react routes here
    'view1',
    'view2'
]) + r'/'
urlpatterns = [
    # Change views.index to whatever your view is
    re_path(react_views_regex, views.index),
]

这些URL应该在有或不带有尾随的情况下使用,对案例敏感(如真实路线),并且只能匹配完整单词(因此,诸如"用户"one_answers"用户"之类的视图不会冲突)。

在django应用程序(app)urls中使用hashrouter代替browserrouter或手动键入react-router-dom path。