UpdateView requires pk, where can I pull that value?

I have got to a better job of refrencing what I am talking about…

"Now, you’ve also got a similar issue with your success_url attribute. Two things there:

  • You’re trying to reverse the same url, which means your reverse_lazy call also needs to include a parameter.
  • You can’t use a dynamically defined function for the success_url attribute. → okay so I am not to use dynamically defined functions for success_url attribute. → I will look at the documentation and try to figure out why this is not a good idea.

You need to override the get_success_url method instead → I will need to research that.

“An UpdateView (or subclass thereof) exists to update an instance of an object. You need to specify for the view which instance is going to be updated. In 99.999% of the cases, this is done by supplying the pk of the instance as a parameter in the url.” → so I went into the model and the model = was Ingredient. but that was incorrect. it was lowercase ingredient. so going forward should I just put in the template pk.model → model being lowercased?

I am discovering all sorts of things about django today that I need to research and understand. I will try to get on Youtube asap.

I could have worded this better. When defining an attribute for a CBV, you don’t want to define them using any functions that are intended to return difference values at different times or under different circumstances.

This is a Python issue and not a Django issue. See 9. Classes — Python 3.11.5 documentation. Once you understand what a Python class is, and the difference between a class attribute and an instance attribute, this will become clear.

When trying to understand the Django-provided CBVs, I always point people in the direction of the Classy Class-Based Views site and the CBV diagrams page. They really are extremely valuable resources.

It would be modelname.pk, not pk.modelname. The UpdateView.get_context_object_name method adds an entry to the context with the key of the lower-case model name.

Or, you can make your templates more generic by just using the name object.

Do yourself a favor - be extremely cautious when selecting YouTube videos. Make sure you select ones known to be current and accurate. (I generally recommend people look at the Awesome Django page for references that have been checked out.)

I think that the main issue is a bad logic in the page you show. You have a page showing a list of ingredients (so not tied to one single ingredient) and a global menu with a link pointing to a page dedicated to the update of one single ingredient. If your page for updating ingredients is a page for updating the whole list of ingredients, either it cannot use an UpdateView (tied to a single object) or it’s an UpdateView for an object that is not an single Ingredient, but the object grouping those ingredients (a Cart, a Receipe, …)

Your right, I need to be able to target each indivdiual ingredient.

I am thinking I need to complete the three books William S Vincent wrote, Django For Beginners, Django for APIS, and Django for Professionals. There are just so many do an don’ts that I do not know about and it shows.

Its my very first project and the code is really bad and it shows.
I will have to research a way to update these ingredients.

You really don’t.

Everything you need to know for everything you’re showing you want to do here is all covered by the Official Django Tutorial, and probably by extension, the “Django for Beginners” book.

There’s no topic, or technique that you need to know yet that goes beyond that.

What I believe you need to focus on more is understanding the fundamentals. Don’t overload yourself with concepts and ideas that are only going to confuse you more.

I think you’d be better served by working your way through the official tutorial again. This time, look at every individual line that you are typing, and test yourself with the question - “What exactly is this line doing and why is it here.”

Then work on generalizing that in your mind to understand how you would apply that principle to other projects.

A class is a blueprint for creating objects or instance objects.
An object attribute is an attribute tied to an object that was created from a class. It is not inherent from the class blueprint.

Going over tutorial now.

There’s a difference between a Class attribute and an Instance attribute.

A Class attribute is going to be the same value across all instances of that class. An Instance attribute is unique to an individual instance.

Additionally, Class attributes are set at the time that the class is imported - they are not recalculated when instances of that class are created.

The variable named success_url is a class attribute. If it calls a function, that function is going to be called once, when the class is loaded. It’s not something that is going to be called every time an instance of a class is created.

So because the success_url is a class attribute it will only run once when the class is loaded. I do not want any functions intended to return difference values at different times or under different circumstances because I would be stuck with what the class attribute would be at the time it is imported.-> am I on the right track?

“Yes, the url you’re trying to reverse needs to be reversed in a get_success_url method, not as being assigned to the success_url attribute of the class.”

per the documentation get_success_url: Determines the URL to redirect to when the form is successfully validated. Returns success_url by default.

Determine the URL to redirect to when the form is successfully validated. Returns success_url by default.

I do not want my attribute to be set once using success_url so I use get_success_url because it will grab the correct url at the time needed where success_url will grab it just once and it stays that value while importing. Is this why I would want to use get_success_url? When I am working in class based views should I be using get_success_url as the default?

I am really struggling with this issue.

It depends.

For a lot of questions like these, there is no single answer - it’s all context sensitive.

For example, one pattern is that “Page 1” displays a list of objects, each object having a link to an edit page (“Page 2”). When someone goes to “Page 2” and submits updated data, the site is supposed to return them to “Page 1”. In this case, every instance of “Page 2” is going to redirect the user to the same page, “Page 1”. This means that it would be appropriate to use success_url.

In a different situation, let’s say that “Page 2” is supposed to forward them to “Page 3” to edit some other, related data. In this case, each instance of “Page 2” needs to redirect the user to a different “Page 3”, based upon what was done on “Page 2”. In this case, you would want to use get_success_url because you’re not always going to redirect every user to the same page.

In my django delights project I have two pages that deal with ingredients. One page is just for displaying all of the ingredients. The other page, ingredient update is used to update the ingredients that are displayed on the page and than route them to the ingredients page.

" For example, one pattern is that “Page 1” displays a list of objects, each object having a link to an edit page (“Page 2”). When someone goes to “Page 2” and submits updated data, the site is supposed to return them to “Page 1”. In this case, every instance of “Page 2” is going to redirect the user to the same page, “Page 1”. This means that it would be appropriate to use success_url ."

It sounds like for my django delights project I would use success url. But you have told me that I need to use get_success_url however in my project there is no third page. Can you clarify why I would need to use get_success_url for my django delights project? Does it have somethign to do with class attributes and they are evaluated only once at import?

IF you were trying to redirect them to your ingredients listing page, then you would be able to use success_url.

But that’s not the url you were trying to reverse. You’ve been trying to reverse ingredientupdate.

So I want my

# urls.py 
from django.contrib import admin
from django.urls import path, include
# from inventory.views import finance, home, IngredientsView, MenuView, PurchaseView
from inventory import views # with every view imported you need to specify views.viewname as seen in this file in the code below
from django.views.generic.base import TemplateView
from django.http import HttpResponse

urlpatterns = [
    
    path('', views.home, name='default'), # users don't need to see the rocket page anyway. they need to see the home page.
    path('admin/', admin.site.urls),
    path('finance/', views.finance, name='finance'),
    path('home/', views.home, name='home'), #I am attempting to connect the home_view function with the views function.
    path('ingredients/', views.IngredientsView.as_view(), name='ingredients'),
    path('menu/', views.MenuView.as_view(), name='menu'),
    path('purchases/', views.PurchaseView.as_view(), name='purchases'), 
    path('menu/add/',views.MenuAdditionView.as_view(success_url = "/menu/"), name="menuadd"),
    path('ingredients/add/', views.IngredientAdditionView.as_view(success_url = "/ingredients/"), name='ingredientadd'), # if class based view it requires an as_view
    path('ingredient/update/', views.UpdateIngredientView.as_view(success_url = "/ingredients/"), name='ingredientupdate'),
    path('recipe/add/', views.RecipeRequirementAdditionView.as_view(success_url = "/menu/"), name='recipeadd'),
    path('purchases/add/', views.PurchaseAdditionView.as_view(success_url = "/purchases/"), name = 'purchaseadd'),
    path('update/inventory/<int:pk>/', views.IngredientsListUpdateView.as_view(), name='updateinventory'), # update view so the view had to be edited.
    # cannot have conflicting path names or matching names
    # finance is not a classed based view therefore i do not need an as_view
    # error message views.finance() type error means I a. calling the fucntion wrong or I am not supposed to be calling it.
    # It needs to know what it is updating. 
    ]

views.py

from django.shortcuts import render
from django.urls import path, reverse_lazy
from .models import Ingredient, MenuItem, Purchases, RecipeRequirement
from django.views.generic import ListView
# import one at the time write the view for it hook it up in urls.py check if it works than move on to the next one. 
from .forms import MenuAdditionForm, IngredientAdditionForm, UpdateIngredientForm, RecipeAdditionForm # link the views and forms togather on this line
# errors can come from importing on the wrong django.views
from django.views.generic.edit import CreateView, UpdateView
from django.http import HttpResponse

# Create your views here.

def finance(request):
    purchased_items = Purchases.objects.all() # this grabs every row in the purchases table

    total_revenue = 0 
    for item in purchased_items:
        total_revenue = total_revenue + item.menu_order.price #this uses the price of each item to calculate the revenue
    
    print(str(total_revenue))
    total_cost= ingredient_cost_calculate()
    print(str(total_cost) + " this is the total cost calculation")

    total_profit= total_revenue - total_cost
    print(str(total_profit) + "total profit calculation amount")

    return render(request,'inventory/finance.html', {"total_revenue": total_revenue, "total_cost":total_cost, "total_profit": total_profit})    
    # i want the price of the item and the cost of each item.
    # what holds this information? my ingredient model. 
    # it holds the price per unit and the unit.
def ingredient_cost_calculate(): 
    # classes do not store information objects do. 
    # i need the cost per ingredient multiplied by quantity used.
    # I need to than for loop over all of the ingredients in a recipe and than apply the cost per ingredient function or 
    # the same mathematical operation. 
    # classes do not have the data, the objects do.
    # when the customer purchases something an entry is made in the purchases table. 
    # Purchases.objects.all() grabs all of the Purchases data and puts it in a list.
    purchases_objects = Purchases.objects.all() 
    # I need to find all of the ingredients per order. How do I get one order to find the ingredients on. 
    # I need to use a for loop to access each purchase. 
    menu_order_cost = 0 
    for purchase in purchases_objects:
        menu_item_object = purchase.menu_order 
        # recipe requirements is a list of data
        recipe_requirements = RecipeRequirement.objects.filter(recipe=menu_item_object)
        # we iterate over that list with a for loop and access the iteration variable quantity fields. 
        
        for requirement in recipe_requirements: 
            cost_per_ingredient = requirement.quantity * requirement.ingredient.price_per_unit
            menu_order_cost = menu_order_cost + cost_per_ingredient
    return menu_order_cost

    

    # the purchases are listed by names they do hold the ingredient data for each indvidual order. 



def home(request):
    return render(request,'inventory/home.html')

class MenuView(ListView):
    # when we specify the model being used for the template its almost as if we import or give access
    # to the html template the class data for us to use for loops and django code on. 
    model = MenuItem
    template_name = 'inventory/menu.html'

class PurchaseView(ListView):
    model = Purchases
    template_name = 'inventory/purchases.html'

class IngredientsView(ListView):
    model = Ingredient
    template_name = "inventory/ingredients.html"

class IngredientsListUpdateView(ListView):
    model = Ingredient
    template_name = "inventory/ingredients_update.html"
    
    
class MenuAdditionView(CreateView):
    model = MenuItem
    template_name = "inventory/form_template.html"
    form_class = MenuAdditionForm
    # fields = ["name", "description", "price"]

class IngredientAdditionView(CreateView):
    model = Ingredient
    template_name = 'inventory/form_template.html'
    form_class = IngredientAdditionForm

class UpdateIngredientView(UpdateView): # I am thinking this is an UpdateView
    model = Ingredient
    template_name = 'inventory/form_template.html'
    fields = ["quantity", "price_per_unit"]
    # success_url field attribute and reverse_lazy are used with updateview. upon successful completion of the viewd django
    # will route the user to the url with the name pattern of ingredientupdate
    success_url = reverse_lazy('ingredientupdate') 
    # fields = we need to input the fields of the columns that the provided model has.
    # per ken I need the get_success_url method. 

class RecipeRequirementAdditionView(CreateView):
    model = RecipeRequirement
    template_name = 'inventory/form_template.html'
    fields = ["ingredient", "recipe", "quantity"]

class PurchaseAdditionView(CreateView):
    model = Purchases
    template_name = 'inventory/form_template.html'
    fields = ["menu_order", "timestamp"]

# update view will require a <pk> or slug where I specify what I need to update.
# check out the codecademy section.
# https://www.codecademy.com/paths/build-python-web-apps-with-django/tracks/views-in-django/modules/django-writing-more-views/lessons/django-views/exercises/using-primary-keys-in-urls


# create a view based on the forms made.
# create a path to urls.py

#form_template.html

{% extends "inventory/base.html" %}
{% block content %}
<form method="POST">
  {% csrf_token %}
  {{ form.as_p }}
  <input type="submit" value="Submit"/>
</form>
{% url 'ingredientupdate' ingredient.pk %}
{% endblock %}

So when I click on the ingredient update page it will not load at all. It says I need a primary key or slug argument. Its intended purpose is to load that new page and I can select ingredients from the list and update them. Upon success of its mission it is routed to the ‘ingredientupdate’ page reloaded with the updated values.

The problem is theIngredient Update page will not load to begin with. Leaving out the int:pk it is asking for a primary key. So somehow, some way I need to get the primary key or the slug in the url. I cannot supply it in the url conf as it does not accept values there. I would supply it in either the views.py or the tempalte. You told me the template is the place to supply those values.

So I made a url tagg with ‘ingredientupdate’ and ingredient.pk and this supplies the primary key value to the url? Right now I am getting an error, django is saying I have not given it any information.

I will continue to work through the tutorial to find this answer.

okay I think I get it. I have been ordering django to take the success_url to the wrong page. I want it routed to the ingredients page. which has a name of ‘ingredients’

success_url = reverse_lazy('ingredients') 

By making this change I am telling Django upon success to route the user to the ingredients page to see the updated quantities.

I observe in my urls that some of these paths have success_urls already. So I can place success_urls in my paths and in my views correct? Would it not be better to have them in one place such as the urls.py file?

# urls.py 
from django.contrib import admin
from django.urls import path, include
# from inventory.views import finance, home, IngredientsView, MenuView, PurchaseView
from inventory import views # with every view imported you need to specify views.viewname as seen in this file in the code below
from django.views.generic.base import TemplateView
from django.http import HttpResponse

urlpatterns = [
    
    path('', views.home, name='default'), # users don't need to see the rocket page anyway. they need to see the home page.
    path('admin/', admin.site.urls),
    path('finance/', views.finance, name='finance'),
    path('home/', views.home, name='home'), #I am attempting to connect the home_view function with the views function.
    path('ingredients/', views.IngredientsView.as_view(), name='ingredients'),
    path('menu/', views.MenuView.as_view(), name='menu'),
    path('purchases/', views.PurchaseView.as_view(), name='purchases'), 
    path('menu/add/',views.MenuAdditionView.as_view(success_url = "/menu/"), name="menuadd"),
    path('ingredients/add/', views.IngredientAdditionView.as_view(success_url = "/ingredients/"), name='ingredientadd'), # if class based view it requires an as_view
    path('ingredient/update/', views.UpdateIngredientView.as_view(success_url = "/ingredients/"), name='ingredientupdate'),
    path('recipe/add/', views.RecipeRequirementAdditionView.as_view(success_url = "/menu/"), name='recipeadd'),
    path('purchases/add/', views.PurchaseAdditionView.as_view(success_url = "/purchases/"), name = 'purchaseadd'),
    path('update/inventory/<int:pk>/', views.IngredientsListUpdateView.as_view(), name='updateinventory'), # update view so the view had to be edited.
    # cannot have conflicting path names or matching names
    # finance is not a classed based view therefore i do not need an as_view
    # error message views.finance() type error means I a. calling the fucntion wrong or I am not supposed to be calling it.
    # It needs to know what it is updating. 
    ]

That is not an accurate statement.

Briefly, do yourself a favor and ignore this topic for now. It’s very unlikely that the real difference between the two is going to matter to you yet.

Quite frankly, you generally can ignore the difference between reverse and reverse_lazy, unless you are using reverse in one of those situations where you need to use reverse_lazy - in which case, the error message is usually quite clear.

Or, you can be “safe” about it and use reverse_lazy everywhere.

(The docs for reverse_lazy show the most common situations where it’s needed.)

There are situations where you can specify success_url in the path definition.

However, I generally recommend against doing it that way, because you’re usually looking for the success_url when you are looking at the view to understand what page(s) it’s going to redirect you to. If you’re looking at the view, then it’s usually more useful to you to see the success_url there, rather than needing to find the url definition for that view.

About the only time I think I might recommend defining attribute like that in the path definition would be those cases where I have a truly generic view being used by multiple URLs, and the value of that attribute depends solely upon what the url is that is calling that view.

So yes, I do agree that it’s generally better to specify those attributes in one place, but my opinion is that that one place should be the view - with a small handful of well-defined exceptions to that.

Yes, an UpdateView updates an instance of an object. The view needs to know which instance to update. → that right there is what I need to understand. Based on our prior conversations ingredients is the model that holds the quantity and price per unit values. I know that Django produces primary key values incrementally. I need to access the object. I tried using int:pk but that did not work. I tried doing it without any path converter and it it says int:pk is needed. So than I tried and now I am getting no reverse match error.

Reverse for ‘ingredientupdate’ with no arguments not found. 1 pattern(s) tried: [‘ingredient/update/(?P[^/]+)\Z’].

Now, you have told me that I need to fix my reverse by supplying the pk. I was looking at the path converters options list.

str
int
slug
uuid
path

I looked up the issue and apparently you can use by itself. I have selected that to see if that would work. I get a no reverse match error now.

I looked at the documentation and it said I could supply parameters using args or kwargs

path(‘ingredient/update/’, views.UpdateIngredientView.as_view(success_url = “/ingredients/”), name=‘ingredientupdate’),

Per what you said.
“You’re trying to reverse the same url, which means your reverse_lazy call also needs to include a parameter.” You also said that I need to overwrite the get_success_url method instead of it being a class attribute."

So I attempt to do so.

According to the documentation I can input parameters with args
django.urls utility functions | Django documentation | Django"

I observed that my reverse_lazy was used inside the get success attribute so I deleted the reverse_lazy and the class attribute and tried to write a function that would overwrite the get success url method.

class UpdateIngredientView(UpdateView): # I am thinking this is an UpdateView
    model = Ingredient
    template_name = 'inventory/form_template.html'
    fields = ["quantity", "price_per_unit"]
    # success_url field attribute and reverse_lazy are used with updateview. upon successful completion of the viewd django
    # will route the user to the url with the name pattern of ingredientupdate
    get_success_url = 
    # fields = we need to input the fields of the columns that the provided model has.
    # per ken I need the get_success_url method. 

class UpdateIngredientView(UpdateView): # I am thinking this is an UpdateView
model = Ingredient
template_name = ‘inventory/form_template.html’
fields = [“quantity”, “price_per_unit”]
# success_url field attribute and reverse_lazy are used with updateview. upon successful completion of the viewd django
# will route the user to the url with the name pattern of ingredientupdate
def get_success_url(‘ingredientupdate’):

@KenWhitesell I am sorry to bother you with all of these questions but I am having a really difficult time trying to fix these errors. I have reviewed the django tutorial and I see where it talks about urls in part 3

The thing is, I have been at this problem for months and I am at my wits end.
I tried inputting just option by itself and it seems to work.
I have a new error NoReverse match at ingredient update.
Reverse for ‘ingredientupdate’ with no arguments not found. 1 pattern(s) tried: [‘ingredient/update/(?P[^/]+)\Z’]
I am told to overwrite the get success url method but the documentation is not telling me what to pass in.
I have tried reading the django documentation but get_success_url does not explain what to pass in. Can I have some advice?