I am working through a basic django tutorial and I have become stuck. When the favorites button is clicked I am trying to redirect the user to reviews/favorite, which will then redirect to reviews/review_id, which is where they started. Instead, whenever I click the favorite button on the page it redirects me to reviews/reviews/review_id which fails.
Interestingly enough if I remove the /reviews/ part from the form action in single-review.html then it routes me to /favorite, which fails because it doesnt exist, but when I put it back to reviews/favorite I go back to reviews/reviews/favorite as the routing. Anyone know what I am doing wrong?
Views.py
from django.http.response import HttpResponse from django.shortcuts import render from django.http import HttpResponseRedirect from django import forms from django.views import View from django.views.generic.base import TemplateView from django.views.generic import ListView from django.views.generic.detail import DetailView from django.views.generic.edit import FormView, CreateView from .forms import ReviewForm from .models import Review # Create your views here. # uses createview to handle all the data processing and then save data to database. Removes need for class ReviewForm in forms.py unless you want to customize class ReviewView(CreateView): model = Review form_class = ReviewForm template_name = "reviews/review.html" success_url = "/thank-you" class ThankYouView(TemplateView): template_name = "reviews/thank-you.html" # method allows you to set items to the context dictionary and them import that data into the thank-you.html file via the message variable def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["message"] = "This Works!" return context class ReviewsListView(ListView): template_name = "reviews/review-list.html" model = Review # do not instantiate when pointing to model context_object_name = "reviews" class SingleReviewView(DetailView): template_name = "reviews/single-review.html" model = Review class AddFavoriteView(View): def post(self, request): print(request) review_id = request.POST["review_id"] request.session["favorite_review"] = review_id return HttpResponseRedirect("reviews/" + review_id)
Models.py
from django.db import models # Create your models here. class Review(models.Model): user_name=models.CharField(max_length=100) review_text=models.TextField() rating = models.IntegerField()
Forms.py
from .models import Review class ReviewForm(forms.ModelForm): class Meta: model = Review fields = "__all__" labels = { "user_name": "Your Name", "review_text": "Your Feedback", "rating": "Your Rating" } error_messages = { "user_name": { "required": "Your name must not be empty!", "max_length": "Please enter a shorter name!" } }
Urls.py in /reviews
from django.urls import path from . import views urlpatterns = [ path("", views.ReviewView.as_view()), path("thank-you", views.ThankYouView.as_view()), path("reviews", views.ReviewsListView.as_view()), path("reviews/favorite", views.AddFavoriteView.as_view()), path("reviews/<int:pk>", views.SingleReviewView.as_view()),
Urls.py in project folder
from django.contrib import admin from django.urls import path, include from django.conf.urls.static import static from django.conf import settings urlpatterns = [ path('admin/', admin.site.urls), path("", include("reviews.urls")), path("profiles/", include("profiles.urls")) ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Settings.py
""" """ Django settings for feedback project. Generated by 'django-admin startproject' using Django 4.0.1. For more information on this file, see https://docs.djangoproject.com/en/4.0/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/4.0/ref/settings/ """ from pathlib import Path # 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.0/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = 'django-insecure--#-h(v7)m6p4rr&fs#7&caa9!$w4!#xzhkioljoy34v3@o!%@%' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [ 'reviews', 'profiles', 'feedback', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ] 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 = 'feedback.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 = 'feedback.wsgi.application' # Database # https://docs.djangoproject.com/en/4.0/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } } # Password validation # https://docs.djangoproject.com/en/4.0/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.0/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.0/howto/static-files/ STATIC_URL = 'static/' #STATICFILE_DIRS = BASE_DIR / "uploads" / "image" # Default primary key field type # https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' #path for files to be stored MEDIA_ROOT = BASE_DIR / "uploads" MEDIA_URL = BASE_DIR = "/user-image/" #you can define the URL to whatever you want between '/ /' # SESSION_COOKIE_AGE = 2592000 #sets how long cookies will last
Single Review HTML Page
{% extends "reviews/base.html" %} {% block title %}Review Detail{% endblock %} {% block content %} <h1>{{ review.user_name }}</h1> <p>Rating: {{ review.rating }} </p> <p>{{ review.review_text }}</p> <form action='/reviews/favorite' method='POST'> {% csrf_token %} <input type="hidden" name="review_id" value="{{ review.id }}" /> <button>Favorite</button> </form> {% endblock %}
Advertisement
Answer
You should use a leading slash in the HTTP redirect response:
class AddFavoriteView(View): def post(self, request): print(request) review_id = request.session['favorite_review'] = request.POST['review_id'] return HttpResponseRedirect(f'/reviews/{review_id}')
If you give the path a name, like:
path('reviews/<int:pk>', views.SingleReviewView.as_view(), name='review-details'),
then you can use redirect(…)
[Django-doc] to determine the URL and return the proper HTTP redirect response:
from django.shortcuts import redirect class AddFavoriteView(View): def post(self, request): print(request) review_id = request.session['favorite_review'] = request.POST['review_id'] return redirect('review-details', pk=review_id)