35

I am using reactjs as a frontend and django as backend. React router is used for routing. When i refresh the page that has routed by react router, i get django 404 Page Not Found error. If i refresh the homepage, i dont get any such error because the homepage is rendered by django template too using its url.

Do i have to configure that in the webpack? My project structure is i have seperated django and reactjs. I have created a folder as frontend where reactjs file resides.

UPDATE

homepage template has all the link for routes like addrestaurant.

my webpack.config file

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)
          );
      },
}

Banner is a child component of App component

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;
5
  • My project structure is same as yours. I didn't have to do any kind of extra url configuration anywhere. Can you share the file where you have defined your routes. And also the file where you have defined the django url Commented Nov 27, 2016 at 7:49
  • django routes or reactjs? Commented Nov 27, 2016 at 10:55
  • Your react router is not having a path. Last time I used React router, I had to specify path attribute. Is this a new way of using react router? Commented Nov 27, 2016 at 12:16
  • its a react router v4 Commented Nov 28, 2016 at 1:21
  • Add url(r'^(?:.*)/?$', base_view), in urls.py file. Commented Sep 15, 2020 at 2:14

6 Answers 6

40

The issue is probably that you haven't configured your URLs to handle the routes that are defined in React Router. In your Django urls.py you should be using a catch all to match all URLs to your index template

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

The base_view would be a view function that renders a template which includes your bundled app.

Sign up to request clarification or add additional context in comments.

8 Comments

Is it still a 404 error or is it an issue with your React app?
my browser got hang.
I'm not really sure what you mean. Your browser is freezing when you try to load your project? I'm not sure what would cause that unless you have an infinite loop somewhere. You probably need to do some dev tools debugging. Is it at least loading the correct page now?
Hi Paul S, I stumbled upon this question cause I have the same issue. Not really a Django girl, so could you please tell me what should I put in base_view?
In case you have other URLs in your stack (I use django's built-in login/logout views), make sure you add the catch-all URL at the bottom of your URL stack.
|
28

In case anyone has this same problem, in django 2.0, follow 'Kevin Martin Jose' answer but instead, replace url with 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')),
]

2 Comments

Thank you! This really worked. I had 2 separate django apps one for the django-rest and the other for the react. I only needed to place the the re_path in the frontend app (the react part) in my urls.
My case as well. Of course, just in case, the frontend's urls.py's urls should be included last in your main app's urls.py or else we're going to swallow API requests and return app.html for them instead of their actual responses :D
7

In case someone's wondering, I had the exact problem and Paul S's answer solved it. Adding an answer instead of comment only because SO does not let me format code snippets inside comments. I ended up using a mixture of django's new path() and the old urls() in my urls.py:

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 handles the login, logout and the root /. React router handles everything else

1 Comment

"re_path" is the new name for the old "url" for those who see this.
4

Here is an answer inspired by the Kevin Jones and Paul S answers. I was having issues with the regex and hosting a REST API. If my front-end app ever didn't append the slash when making API calls, it wouldn't match and it would get routed back to the front end. This is because the django setting APPEND_SLASH=True requires that it goes through urlpatterns and fails once before it appends the slash and tries again. Therefor, here is a regex that just excludes anything starting with 'api' or 'admin' and otherwise sends it on to the front end.

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")),
] 

1 Comment

thanks for the check of api/admin.. Can add meda/static urls also to exclude
1

Here's a solution that does not cause overrides of other views, and doesn't require you to trash your 404 handler.

The disadvantage is this requires keeping an up-to-date list of your routes, but that's what this file is meant for.

In 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),
]

These URLs should work with or without a trailing slash, are case-sensitive (like real routes), and will only match the full word (so views like 'user' and 'users' will not conflict).

Comments

0

Use HashRouter instead of BrowserRouter or manually type react-router-dom path in Django application (app) urls.

2 Comments

Can you explain why it works?
This happens between server and client side, in this case you specify the path on client side using react router, it actually works using window.location.pathname. you reload the page the server checks the path exists on the server side, that's why you have. There is no page error, but you are using HashRouter and the server does not know the contents of the path after the hashtag. refer: stackoverflow.com/a/51976069/18568151

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.