Django Grabing form input and edit an instance


(Khalil Mehtal) #1

hi Vitor hi everyone ,

i’m trying to make a simple inventory app but i’m have trouble with restock logic for instance if i have a new stock bought with diffrent price than the first one i want just get the average price on the whole stock in shell works fine but when i go to my form i always get the form input instead of the desired value, after some investigation i found out that i’m grabbing the instance data using request.POST.get and even before the form.save() , how can i grab my input data and the object instance separately so i can use the logic bellow

##models 
class Supply(models.Model):
    name = models.CharField(max_length=100, unique=True)
    quantity = models.PositiveIntegerField()
    price = models.DecimalField(max_digits=11, decimal_places=2)
    created = models.DateField(auto_now_add=True)
    last_modefied = models.DateField(auto_now=True)

    def __str__(self):
        return self.name
##form
class SupplyForm(forms.ModelForm):
    class Meta:
        model = Supply
        fields = ["name", "quantity", "price"]
#view
def add_supply(request):
    form = SupplyForm()
    if request.POST:
        # getting form input data
        name = request.POST.get("name")
        quantity = request.POST.get("quantity")
        price = request.POST.get("price")
        # getting Supply instance
        item = Supply.objects.get(name=name)
        # instantiating the form
        form = SupplyForm(request.POST, instance=item)
        if form.is_valid:
                # Logic
            old_supply = item.quantity * item.price
            new_supply = int(quantity) * int(price)
            new_quantity = item.quantity + int(quantity)
            item.price = (old_supply + new_supply) / new_quantity
            item.quantity = new_quantity
            form.save()
            return redirect("project_list")
    return render(request, "restock.html", {"form": form})

(Khalil Mehtal) #2

found this answer to who ever might need it : 1st remove modelform and make a form.Forms with 2 new fields something like that

#forms
      class RestockForm(forms.Form):
            name = forms.CharField(max_length="30")
            quantity = forms.IntegerField(min_value=0)
            price = forms.DecimalField(max_digits=11, decimal_places=2)
            new_quantity = forms.IntegerField(min_value=0)
            new_price = forms.DecimalField(max_digits=11, decimal_places=2)

#views
    def add_supply(request, pk):
        #getting the object
        item = get_object_or_404(Supply, pk=pk)
        # instantiating the form on using initial since its not a model form
        form = RestockForm(initial={"name": item.name, "quantity": item.quantity, "price": item.price})
        if request.POST:
            # getting form extra input data
            quantity = request.POST.get("new_quantity")
            price = request.POST.get("new_price")
            form = RestockForm(request.POST,)
            if form.is_valid():
                old_supply = item.quantity * item.price
                new_supply = int(quantity) * int(price)
                _quantity = item.quantity + int(quantity)
                item.price = (old_supply + new_supply) / _quantity
                item.quantity = _quantity
                # important need to save the object
                item.save()
                return redirect("project_list")
        return render(request, "restock.html", {"form": form})
#urls
path('restock/<int:pk>', stock_views.add_supply, name="restock"),

(Vitor Freitas) #3

Great that you found a solution for your problem :smiley:

Depending on the case, if you are loading a model form to edit, you could do something like this:

class SupplyForm(forms.ModelForm):
    def clean(self):
        cleaned_data = super().clean()
        old_supply = self.instance.quantity * self.instance.price
        new_supply = cleaned_data.get('quantity') * cleaned_data.get('price')
        # add your business logic/validation
        return cleaned_data  # always return the cleaned data

But this form would break if you try to add a new Supply, because there would be no instance. So it would only work if you initialize the form like:

form = SupplyForm(request.POST, instance=supply)

(Khalil Mehtal) #4

thanks dude this helps a lot i didn’t know that i can add new form fields to modelform so shied away from using it , Using it your way is way clearer and easier i just add some business logic in the clean method , saved the instance and hook it to an UpdateView and i’m done with it