Attribute Error at update/inventory

Hello Django Forum! After trying to search on stack overflow and on the django forum website I have been unable to find an answer for this error specific to my case. In general what does this error mean?
Does it have to do with a primary key? (pk) What is a slug?

I believe a slug is:
A Slug is the unique identifying part of a web address, typically at the end of the URL. In the context of MDN, it is the portion of the URL following "/docs/ ".

urls.py

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(), 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', views.UpdateIngredientView.as_view(success_url = "/ingredients/"), name='updateinventory'), # my goal on this line of code is update the inventory for an existing ingredient.
    # 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.
    ]

views.py

from django.shortcuts import render
from django.urls import path 
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 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"]
    # fields = we need to input the fields of the columns that the provided model has.

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

models.py

from django.db import models

# Create your models here.

class Ingredient(models.Model):
    name = models.CharField(max_length = 20)
    quantity = models.FloatField()
    unit = models.CharField()
    price_per_unit = models.FloatField()
# keep in mind that if you do use updateview you do not want to provide update view access to fields that you do not want edited in the column. 
# this could result in users messing up things that they should not be allowed to touch.
    
    def __str__(self): # without the def_str__ method it will not label ingredient by name
        return " " + self.name

class MenuItem(models.Model):
    name = models.CharField(max_length = 20)
    description = models.CharField(max_length = 200)
    price = models.FloatField()
    # I have set a primary key in hopes of having some way to identfy what has been ordered?
    # id = models.AutoField(primary_key=True) 
    
    def requirements(self): # made for purchases sake and menu.html sake
        requirements = RecipeRequirement.objects.filter(recipe=self)
        return requirements
        # this function will will grab all of the objects in the receipe requirements table
        # and than it will filter what it grabs by the recipe being used and only grab what 
        # ingredients the recipe calls for. 
        # .filter will leave things as a list.  
        # ingredients is a method on the object. 
        # ingredient 

    def __str__(self):
        return self.name

        # go to the Receipe Requirements table.grab all of the recipe requiement data attributes. through .objects method. 
        # using.filter we tell python to only give me the objects when they equal this recipe. 
        # recipe is an attribute in the RecipeRequirement table line 44 see below.
        # when that recipe field is equal to self grab the items that were used in making the recipe. 
        # self is an instance of an object. and that was 
        # when this item is equal to the one listed in the recipe grab this value. 


        # we need to access the ingredient cost and add it up. price per unit by the amount used and add it up.
        

        #find me all of the recipe items you need to make this receipe. 
        #self is an instnace of the object. 
        #django djaffe cake as a menu item with descriptiona nd price. we pass that object in and say give me the recipe requirement
        # is this object. 



class RecipeRequirement(models.Model):
    # a recipe_id will populate with django here
    ingredient = models.ForeignKey(Ingredient,on_delete=models.CASCADE) # the ForeignKey will automatically reference the primary key that Django makes for us.
    recipe = models.ForeignKey(MenuItem,on_delete=models.CASCADE) # the table did not have a concept of which ingredients were tied to what recipe. this line of code associates ingredients with reciepes.
    quantity = models.FloatField()

    def __str__(self):
        return self.recipe.name + " " + self.ingredient.name # you can access values outside of the class to name things. this line of code details the recipe name and ingredient

class Purchases(models.Model):
    # a purchase_id_field will populate with django here
    menu_order = models.ForeignKey(MenuItem,on_delete=models.CASCADE) # this will let us see what menu items were ordered. # without the str method its an object method that you can use for calculations for purchases
    timestamp = models.DateTimeField()

# menu order points to a row on the menu item table 
# menu item is a table with a primary key called id. 
# python will grab the menu item as an object and all of its data.
# menu order is a column in purchases that will have the menu item id in it. 
# django djaffa cake has one id number. and if coffee has an id of two. it will find things by id number. 
# each recipe has an id number of its own. on line 33 of models.py 
# its saying follow those id numbers.


    class Meta:
        verbose_name = "Purchase"


# ask myself what does this table need information for
# what questions am I trying to answer for my boss or for my project?
# when inside of virtual enviornment just run python 
# python manage.py 

base.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div class="topnav"> <!-- the green text is talking about paths the white is what is on the page-->
    <a href="{% url 'home' %}">Home</a>
    <a href="{% url 'ingredients' %}">Ingredients</a> <!-- name= connection-->
    <a href="{% url 'menu' %}">Menu</a>
    <a href="{% url 'finance' %}">Finance</a>
    <a href="{% url 'purchases' %}">Purchases</a>
    <a href="{% url 'menuadd' %}">Add Menu</a> <!--utilize name in urls.py -->
    <a href="{% url 'ingredientadd' %}">Add Ingredient</a>
    <a href="{% url 'recipeadd' %}">Add Receipe</a>
    <a href="{% url 'purchaseadd' %}">Add Purchase</a>
    <a href="{% url 'updateinventory' %}"> Update Inventory</a>
  </div>

  {% block content %}
  {% endblock %}
</body>
</html>

The Generic Update view is expected to operate on a single instance of a Model (I would assume Inventory in your case). To specify this instance of a model it is configured in the URLconf of the view which would be something like:

path('update/inventory/<slug:slug>', views.UpdateIngredientView.as_view(success_url = "/ingredients/"), name='updateinventory')
# or 
path('update/inventory/<int:pk>', views.UpdateIngredientView.as_view(success_url = "/ingredients/"), name='updateinventory')

Your current URLconf doesn’t have this variable in the “update inventory” URL. You can use a slug or a primary key to get this object.

Also, a helpful reference for class-based views is ccbv.co.uk which has the code nicely formatted to understand what is actually happening.

1 Like

I was told by another developer that is a part of my meetup group for Django that I need to specify the primary key just as you suggested. He told me that Django will automatically assign a primary key to my model in models.py. I think what you are trying to tell me is to have my url target the primary key in my path by typing in int:pk. I have done so and I have a new error message! I consider it progress because it found something!

I searched stack overflow and found python - Django - getting Error "Reverse for 'detail' with no arguments not found. 1 pattern(s) tried:" when using {% url "music:fav" %} - Stack Overflow

Do I need to match ‘updateinventory’ as the error message implies and as stack overflow implies?

According to your error stack, you have fixed the url error now in your views.py UpdateIngredientView for this view you have to pass success_url ="/" like

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 ="/"

Assuming you have now allowed for a Primary Key or slug as per my suggestion.

The error is complaining that in a template you are trying to reverse a URL without specifying which object to update.
It needs to be something like

{% url 'urlname' object.pk %}

I attempted your solution but the same error message remained for some reason.

I attempted your solution by inputting in the Ingredient model as my object.pk. My task is to create a page to update the inventory for an existing ingredient. such as the quantity attribute in my models. I received the following error message.

In this photo see the line number 20 here you are using Ingredient.pk, from where you are passing this Ingredient object to your template. Ingredient has to be instance of your model passed through the view to your template’s context

An instance of my model?
Let me walk through my logic when I am reading your response addwebsolution.

Python has classes which are blue prints for objects. Objects hold the attributes and methods from the class when activated and are usually stored as variables containing the data.

I also know that attributes in models are the column names for the table. → 80% confidence in saying this.

"In this photo see the line number 20 here you are using Ingredient.pk from where you are passing this Ingredient object to your template. "

Ingredient has to be an instance of your model passed through the view to your templates context.

So did I not create the object or instance? What should I do next? How would I have Ingredient be the instance of my model>? How would I pass it into my views template context?

Okay so am I passing in the ingredients attributes →

Just to clarify some concepts and terminology.

Python has classes which can define a concept in a script or application. An object is instantiated from a class. On both of these can exist class attributes and class methods as well as instance attributes and methods. There are important differences between them, but I will leave that reading/experimentation to you for a later time.

In Django, we have Models, which are a specific type of class. They define the schema of a database table through migrations. You can think of the class as a blank database table. If you want to add a row to the database table you need to create an instance of that class either through the constructor of the class and calling save or using the Queryset API.

In your current view, you want to update a specific row of your Ingredient Model(table). To be able to do that you need to reference that specific row, which is a specific instance (object) of that model/class. Currently, you are trying to access the primary key of the table, which doesn’t make sense.

Finally, I cannot remember if I have suggested this already, but these concepts would have been well covered in the official tutorial or the Django girls tutorial. Please take the time to do them until you understand the concepts and it will make you more productive in the long run.