Search code examples
djangodjango-templateshttp-status-code-404

Error 404 - HTML page not rendering for other apps than main application


So I've created several apps in my Django project and I have one main app called main_app.

The other apps are called profile_app, settings_app, messages_app.

The issue:

The issues that I have is that whenever I try to run a certain view function from e.g profile_app in main_app using the app namespace and URL name (e.g profilepage_app:"profile-redirect"), I receive a 404 error stating "Page not found".

I have done the following:

  • Registret all apps.
  • Linked the urls.py file in my settings URL.
  • Tried to create a test view function inside the main_app and it works perfectly, but the same function does not work in the profile_app.
  • Created another test app in order to see if I still have the same issue (I did).

So the problem is that whatever link from all apps (except main_app) that I try to display in the browser generats the "Page not found"-error.

My questions:

  1. Why does this happen?
  2. How can I resolve this issue?
  3. Has this something to do with my settings file?

The error:

My view:

from django.conf import settings
from django.shortcuts import render, redirect
from django.views.generic import View

from profile_app.forms import *
from profile_app.models import *
from messages_app.models import Message

user = settings.AUTH_USER_MODEL
# Create your views here.

## Redirect to user profile from the navbar

class ProfilePageView(View):
    model = ProfilepageMember
    template_name = "profile_app/profilepage.html"
    
    def get(self, request, user_name):
        user_related_data = ProfilepageMember.objects.filter(member__username = user_name)
        context = {"user_related_data": user_related_data}
        return render(request, self.template_name, context)

My URLS:

"""
URL configuration for bodyswap_project project.

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/4.2/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path("admin/", admin.site.urls),
    path("", include("auth_app.urls")),
    path("", include("main_app.urls")),
    path("", include("profile_app.urls")),
    path("", include("messages_app.urls")),
    path("", include("settings_app.urls")),
]


Settings:

"""
"""
Django settings for body project.

Generated by 'django-admin startproject' using Django 4.2.

For more information on this file, see
https://docs.djangoproject.com/en/4.2/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.2/ref/settings/
"""

from pathlib import Path
import os
from dotenv import load_dotenv
load_dotenv()

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.getenv("SECRET_KEY")

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = os.getenv("DEBUG")

ALLOWED_HOSTS = []

# HTTPS settings

# Set this to True in production to avoid transmitting the CSRF cookie over HTTP accidentally.
CSRF_COOKIE_SECURE = False
# Set this to True in production to avoid transmitting the CSRF cookie over HTTP accidentally.
SESSION_COOKIE_SECURE = False
# Change to True in production
SECURE_SSL_REDIRECT = False

# HSTS settings

# SECURE_HSTS_SECONDS = 31536000  # 1 year
# SECURE_HSTS_PRELOAD = True
SECURE_HSTS_INCLUDE_SUBDOMAINS = False

# Email settings for the contact form
# Used only during development

EMAIL_HOST = os.getenv("EMAIL_HOST")
EMAIL_HOST_USER = os.getenv("EMAIL_HOST_USER")
EMAIL_HOST_PASSWORD = os.getenv("EMAIL_HOST_PASSWORD")
EMAIL_PORT = os.getenv("EMAIL_PORT")

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # Installed apps
    'main_app.apps.MainAppConfig',
    'auth_app.apps.AuthAppConfig',
    'profile_app.apps.ProfileAppConfig',
    'settings_app.apps.SettingsAppConfig',
    'messages_app.apps.MessagesAppConfig',
]

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 = 'body.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 = 'body.wsgi.application'


# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}


# Password validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators

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',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/

STATIC_URL = 'static/'

STATICFILES_DIRS = [
    BASE_DIR / "static"
]


# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
# This is set when creating a custom user model.
AUTH_USER_MODEL = 'main_app.Member'


I appreciate all help.


Solution

  • Why does this happen?

    You included the profilepage/urls.py module in the URLs, but likely after you included the static paths somewhere.

    How can I resolve this issue?

    You normally define the static and media paths at the root urls.py after all other paths, such that it is only used if the matches of all other paths fail, so:

    from django.conf import settings
    from django.conf.urls.static import static
    from django.contrib import admin
    from django.urls import include, path
    
    urlpatterns = (
        [
            path('admin/', admin.site.urls),
            path('', include('auth_app.urls')),      # 🖘 no static/media urls
            path('', include('main_app.urls')),      # 🖘 no static/media urls
            path('', include('profile_app.urls')),   # 🖘 no static/media urls
            path('', include('messages_app.urls')),  # 🖘 no static/media urls
            path('', include('settings_app.urls')),  # 🖘 no static/media URLs
        ]
        + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
        + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
    )

    It is thus important that the auth_app.urls, main_app.urls, profile_app.urls, messages_app.urls and settings_app.urls do not contains the static/media paths. Strictly speaking that is not a problem either, as long as these are not "wildcards" that will match any path, but as you found out, that is easily the case.

    Has this something to do with my settings file?

    No: The order of the URLs is important: Django will match these top to bottom, and the first pattern that matches will "fire". If you thus have a path pattern that matches any path, it will always fire, and Django will thus never look to any paths further in the chain.

    Subclassing the View class directly is often not necessary. In this case your view looks like a DetailView [Django-doc]. By using a DetailView instead of a simple View, you often do not have to implement a lot of boilerplate code.

    from django.shortcuts import get_object_or_404
    from django.views.generic import DetailView
    
    
    class ProfilePageView(DetailView):
        model = ProfilepageMember
        template_name = 'profile_app/profilepage.html'
        context_object_name = 'user_related_data'
    
        def get_object(self, *args, **kwargs):
            return get_object_or_404(ProfilepageMember, member__username=user_name)