I can't save data from multiple models in a single form

Hi! :wave: I have a problem with my Django application.

I’m creating a web application for a company that allows it to manage the warehouse.

My problem is that I created a very structured database and now I would like to create a page that goes to enter the data without having to use the Django’s admin …

I know the names of the variables are in Italian, but it’s my first serious project and I wouldn’t want to get lost :sweat_smile:

Anyway, this is the structure of my project:

models.py :

from django.db import models

# Create your models here.


class AziendaCity(models.Model):
    city_ID = models.AutoField(primary_key=True, unique=True)
    city = models.CharField(max_length=250, verbose_name='Città')

    class Meta:
        verbose_name = 'Città'
        verbose_name_plural = 'Città'

    def __str__(self):
        return self.city


class AziendaAddress(models.Model):
    address_ID = models.AutoField(primary_key=True, unique=True)
    address = models.CharField(max_length=250, verbose_name='Indirizzo')

    class Meta:
        verbose_name = 'Indirizzo'
        verbose_name_plural = 'Indirizzi'

    def __str__(self):
        return self.address


class AziendaCap(models.Model):
    cap_ID = models.AutoField(primary_key=True, unique=True)
    CAP = models.IntegerField()

    def __str__(self):
        return str(self.CAP)


class AziendaProvincia(models.Model):
    provincia_ID = models.AutoField(primary_key=True, unique=True)
    provincia = models.CharField(max_length=2)

    class Meta:
        verbose_name = 'Provincia'
        verbose_name_plural = 'Province'

    def __str__(self):
        return self.provincia


class Azienda(models.Model):
    id_azienda = models.AutoField(primary_key=True, unique=True)
    nome_azienda = models.CharField(max_length=250, unique=True)
    email_azienda = models.EmailField(blank=True)
    city_ID = models.ForeignKey(AziendaCity, on_delete=models.CASCADE, verbose_name='Città')
    address_ID = models.ForeignKey(AziendaAddress, on_delete=models.CASCADE, verbose_name='Indirizzo')
    cap_ID = models.ForeignKey(AziendaCap, on_delete=models.CASCADE, verbose_name='C.A.P')
    provincia_ID = models.ForeignKey(AziendaProvincia, on_delete=models.CASCADE, verbose_name='Provincia')

    class Meta:
        verbose_name = 'Azienda'
        verbose_name_plural = 'Aziende'

    def __str__(self):
        return self.nome_azienda


class ProdottoNome(models.Model):
    nome_ID = models.AutoField(primary_key=True, unique=True)
    prodotto_nome = models.CharField(max_length=255, default='')

    class Meta:
        verbose_name = 'Nome Prodotto'
        verbose_name_plural = 'Nome Prodotti'

    def __str__(self):
        return self.prodotto_nome


class Formato(models.Model):
    formato_ID = models.AutoField(primary_key=True, unique=True)
    formato = models.CharField(max_length=250, default='')

    class Meta:
        verbose_name = 'Formato'
        verbose_name_plural = 'Formati'

    def __str__(self):
        return self.formato


class PrezzoPubblico(models.Model):
    prezzo_pubblico_ID = models.AutoField(primary_key=True, unique=True)
    prezzo_pubblico = models.DecimalField(
        max_digits=99, decimal_places=2, default='')

    class Meta:
        verbose_name = 'Prezzo Pubblico'
        verbose_name_plural = 'Prezzi Pubblici'

    def __str__(self):
        return str(self.prezzo_pubblico)


class Prodotto(models.Model):
    product_ID = models.AutoField(primary_key=True, unique=True)
    produttore = models.ForeignKey(Azienda, on_delete=models.CASCADE)
    nome = models.ForeignKey(ProdottoNome, on_delete=models.CASCADE)
    formato = models.ForeignKey(Formato, on_delete=models.CASCADE)
    prezzo_pubblico = models.ForeignKey(PrezzoPubblico, on_delete=models.CASCADE)
    quantity = models.IntegerField(verbose_name='Quantità', default=0)

    class Meta:
        verbose_name = 'Prodotto'
        verbose_name_plural = 'Prodotti'

    def __str__(self):
        return str(self.nome)

    @property
    def statusProduct(self):

        quantity = self.quantity

        ottimo = ' Ottimo '
        riserva = ' Riserva '
        ordinare = ' Ordinare '
        
        if quantity > 100 :
            status = ottimo
        elif 50 > quantity > 40:
            status = riserva
        elif 40 > quantity > 0:
            status = ordinare
        return status

forms.py :

from django import forms
from django.forms import ModelForm, TextInput, Select
from .models import *

# Form Inserimento Prodotto


class ProduttoreForm(forms.ModelForm):
    class Meta:
        model = Prodotto
        fields = ['produttore']
        widgets = {
            'produttore' : forms.Select(attrs={'class':'form-control'})
        }
        


class ProdottoNomeForm(forms.ModelForm):
    prodotto_nome = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control', 'placeholder':'Inserisci il nome del prodotto'}))
    class Meta:
        model = ProdottoNome
        fields = ['prodotto_nome']
        

class ProdottoFormatoForm(forms.ModelForm):
    formato = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control','placeholder':'Inserisci il formato del prodotto'}))
    class Meta:
        model = Formato
        fields = ['formato']


class ProdottoPrezzoPubblicoForm(forms.ModelForm):
    prezzo_pubblico = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control','placeholder':'Inserisci il prezzo pubblico del prodotto'}))
    class Meta:
        model = PrezzoPubblico
        fields = ['prezzo_pubblico']



class ProdottoQuantitàForm(forms.ModelForm):
    quantity = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control','placeholder':'Inserisci la quantità del prodotto'}))
    class Meta:
        model = Prodotto
        fields = ['quantity']


# Form Inserimento Azienda


class AziendaForm(forms.ModelForm):
    class Meta:
        model = Azienda
        fields = '__all__'

views.py :

from django.shortcuts import redirect, render
from django.http import HttpResponseRedirect
from .models import Prodotto, Azienda, ProdottoNome
from .filters import ProductFilter
from .forms import ProdottoNomeForm, AziendaForm,ProduttoreForm,ProdottoFormatoForm,ProdottoPrezzoPubblicoForm,ProdottoQuantitàForm
# Create your views here.


def Magazzino(request):
    prodotti = Prodotto.objects.all
    aziende = Azienda.objects.all
    #prodotto_nome = ProdottoNome.objects.all

    productFilter = ProductFilter(request.GET, queryset=prodotti(),)
    prodotti = productFilter.qs

    return render(request, 'index.html', {'prodotti': prodotti, 'aziende': aziende, 'productFilter': productFilter})


def Aziende(request):
    aziende = Azienda.objects.all

    return render(request, 'aziende.html', {'aziende': aziende})


def inserisciProdotto(request):
    prodotto_nome_form = ProdottoNomeForm
    produttoreform = ProduttoreForm
    prodotto_formato_form = ProdottoFormatoForm
    prezzo_pubblico_form = ProdottoPrezzoPubblicoForm
    prodotto_quantity = ProdottoQuantitàForm
    context = { 'prodotto_nome_form':prodotto_nome_form,
                'produttoreform':produttoreform, 
                'prodotto_formato_form':prodotto_formato_form,
                'prezzo_pubblico_form':prezzo_pubblico_form,
                'prodotto_quantity':prodotto_quantity
                }

    if request.method == 'POST':
        produttoreform        = ProduttoreForm(request.POST)
        prodotto_nome_form    = ProdottoNomeForm(request.POST)
        prezzo_pubblico_form  = ProdottoPrezzoPubblicoForm(request.POST)
        prodotto_formato_form = ProdottoFormatoForm(request.POST)
        prodotto_quantity     = ProdottoQuantitàForm(request.POST)

        if  produttoreform.is_valid() and\
            prodotto_nome_form.is_valid() and\
            prezzo_pubblico_form.is_valid() and\
            prodotto_formato_form.is_valid() and\
            prodotto_quantity.is_valid():

            produttoreform.save(commit=False)
            prodotto_nome_form.save(commit=False)
            prezzo_pubblico_form.save(commit=False)
            prodotto_formato_form.save(commit=False)
            prodotto_quantity.save(commit=False)

            return redirect('')

    return render(request, 'inserisci_prodotto.html', context)

and this is the html page :

{%extends 'base.html'%}
{% load static %}

{% block content %}
<div class="container">
    <br>
    <form action="" method="POST">

        {% csrf_token %}
        <div class="mb-3">
            <label for="produttore" class="form-label">Produttore</label>
            {{produttoreform.produttore}}
            <div id="produttore" class="form-text">Seleziona dalla lista un'azienda</div>
        </div>

        <div class="mb-3 ">
            <label for="prodotto_nome" class="form-label">Nome Prodotto:</label>
            {{prodotto_nome_form.prodotto_nome}}
        </div>

        <div class="mb-3">
            <label for="formato" class="form-label">Formato:</label>
            {{prodotto_formato_form.formato}}
        </div>

        <div class="mb-3">
            <label for="prezzo_pubblico" class="form-label">Prezzo Pubblico:</label>
            {{prezzo_pubblico_form.prezzo_pubblico}}
        </div>

        <div class="mb-3">
            <label for="quantity" class="form-label">Quantità:</label>
            {{prodotto_quantity.quantity}}
        </div>

        <button type="submit" class="btn btn-outline-primary">Inserisci Prodotto</button>
    </form>
    <br>
    <br>
</div>  


{% endblock content %}

When I try to enter data to save, the page updates, as if it had saved the data without giving any error message.

But in reality the data is not saved in the database.

Why?!

Thanks for the support ! :pray:

You are missing a lot of parens in the code as you have it posted here:

For example:

should be:
prodotti = Prodotto.objects.all()

Likewise:

is assigning the Form class to the variable to be passed in the context instead of:
prodotto_nome_form = ProdottoNomeForm()

And this block:

is going to result in the data never being saved.

You only need to use the commit=False clause if you need to get the system-generated primary key before saving that data. IF you do need to do some work like that, then you still need to save the resultant objects.

You’re also not handling the “not-valid” case for the forms - if there’s an error during submission, you won’t see what the problems are.

You might want to take a step back, and simplify this down to just one form until you’ve got it working. Then go to two forms. Then add the rest. You may find it difficult trying to track down the fundamental issues when you’ve got too many variables involved.

1 Like

Thank’s for the answer! I’ll try to simplify my models and working on it!!!
Have a great day!
:pray: :pray: :pray:

Could you post here with your progress? We who read the post can learn from it :wink:

1 Like

Ok … tomorrow morning I’ll post my solution … :wink:

1 Like

Hi! :wave:

That’s the solution that working for me!

At the moment I’ve created only two model, one for the product and on for the company, I have simplified the models a lot in order to create as few operations as possible … later I will integrate it with more advanced models and functions.

In my models.py :

class Company(models.Model):
    company_id = models.AutoField(primary_key=True, unique=True)
    company_name = models.CharField(max_length=250, unique=True, verbose_name='Nome')
    company_email = models.EmailField(blank=True, verbose_name='Indirizzo Email')
    city = models.CharField(max_length=50, verbose_name="Città")
    address = models.CharField(max_length=50, verbose_name="Indirizzo")
    cap = models.CharField(max_length=6, verbose_name="C.A.P.")
    prov = models.CharField(max_length=2, verbose_name="Provincia",)
 
    class Meta:
        verbose_name = 'Azienda'
        verbose_name_plural = 'Aziende'
 
    def __str__(self):
        return self.company_name
 
 
class Prodotto(models.Model):
    product_ID = models.AutoField(primary_key=True, unique=True)
    producer = models.ForeignKey(Company, on_delete=models.CASCADE)
    product_name = models.CharField(max_length=50, verbose_name='Nome') 
    product_format = models.CharField(max_length=10, verbose_name='Formato')
    public_price = models.DecimalField(max_digits=10, decimal_places=2, default=0, verbose_name='Prezzo Pubblico')
    quantity = models.IntegerField(default=0, verbose_name='Quantità')
    quantity_ordered = models.IntegerField(default=0, verbose_name='Quantità Ordinata')
 
    class Meta:
        verbose_name = 'Prodotto'
        verbose_name_plural = 'Prodotti'
 
 
    def __str__(self):
        return str(self.product_name)

In my views.py :

def insertProduct(request):
    product_form = ProductForm()
    context = { 'product_form':product_form }

    if request.method == 'POST':
        product_form = ProductForm(request.POST)

        if  product_form.is_valid():
            product_form.save()

            return redirect('../magazzino')

    return render(request, 'insert_product.html', context)


def update_Price_Product(request, pk):
    product_form = Update_Price_Form()

    product = Product.objects.get(product_ID=pk)
    form = Update_Price_Form(instance=product)

    context = {'form':form, 'product_form':product_form }

    if request.method == 'POST':
        product_form = Update_Price_Form(request.POST, instance=product)

        if  product_form.is_valid():
            product_form.save()

            return redirect('../magazzino')


    return render(request, 'aggiorna_prezzo.html', context)


def update_Quantity_Product(request, pk):
    product_form = Update_Quantity_Form()

    product = Product.objects.get(product_ID=pk)
    form = Update_Quantity_Form(instance=product)

    context = {'form':form, 'product_form':product_form }

    if request.method == 'POST':
        product_form = Update_Quantity_Form(request.POST, instance=product)

        if  product_form.is_valid():
            product_form.save()

            return redirect('../magazzino')


    return render(request, 'aggiorna_quantità.html', context)

But now I have another problem that I would like to ask you, always in the models.py and that’s it :

I’ve implemented my Product model with a 3 property :

  1. one to add up the products, those already in stock plus those that come from a new order.

  2. one to check the status of the product

  3. to change the background color of the product according to the status

That’s the code in my models.py :

class Product(models.Model):
    product_ID = models.AutoField(primary_key=True, unique=True)
    producer = models.ForeignKey(Company, on_delete=models.CASCADE)
    product_name = models.CharField(max_length=50, verbose_name='Nome') 
    product_format = models.CharField(max_length=10, verbose_name='Formato')
    public_price = models.DecimalField(max_digits=10, decimal_places=2, default=0, verbose_name='Prezzo Pubblico')
    quantity = models.IntegerField(default=0, verbose_name='Quantità')
    quantity_ordered = models.IntegerField(default=0, verbose_name='Quantità Ordinata')
 
    class Meta:
        verbose_name = 'Prodotto'
        verbose_name_plural = 'Prodotti'
 
 
    def __str__(self):
        return str(self.product_name)

    @property
    def updateQuantity(self):
        
        update_quantity = self.quantity_ordered
        total_quantity = update_quantity + self.quantity

        return total_quantity
    

    @property
    def statusProduct(self):

        quantity = self.quantity
        total_quantity = quantity + self.quantity_ordered 

        ottimo = ' Ottimo '
        riserva = ' Riserva '
        ordinare = ' Ordinare '
        
        if total_quantity > 100 :
            status = ottimo
        elif 50 > total_quantity > 40:
            status = riserva
        elif 40 > total_quantity >= 0:
            status = ordinare

        return status

    
    @property
    def statusColor(self):

        quantity = self.quantity
        total_quantity = quantity + self.quantity_ordered 

        ottimo = ' #49C71A ' 
        riserva = ' #FFA700 '
        ordinare = ' #D05959 '
        
        if total_quantity > 100 :
            color = ottimo
        elif 50 > total_quantity > 40:
            color = riserva
        elif 40 > total_quantity > 0:
            color = ordinare

        return color

The problem is that I can add the quantity ordered to quantity, and display this, but didn’t work with status property, because at the beginning this property’s working only with the quantity field.

If I try to run this code I’ve this message error :

UnboundLocalError: local variable ‘status’ referenced before assignment

How can I fix that?

Hope this is the right discussion, thank’s!

Assuming this is the block of code where the error is occurring, specifically the last line, then the error is being thrown if all the if conditions were false and status is never getting set. You’ll get this error on any case where `total_quantity is between 50 and 100, or less than 0.

1 Like

… And

What happens if total_quantity is exactly 40?

1 Like

the status code only works if I use the quantity field, not the sum between quantity and quantity_ordered

Considering this to make it work, I modified the code like this :

if quantity > 100 :
            status = ottimo
        elif 50 > quantity > 40:
            status = riserva
        elif 40 >= total_quantity >= 0:
            status = ordinare

And this works … but when I add the sum of the two fields, as in the example posted before … the error returns to my screen

Yes, but I set that the initial products are equal to 500 … if it were as you say then the code should work …
But at present I still have this mistake :sob:

Please post the complete traceback message. You either have a logic error in your view, or a data error in your model. There’s not enough information here to determine what the cause may be.

The direct and immediate source of the error, assuming I’ve guessed the right block of code being referenced by the error, is that none of those conditions are testing as True.

1 Like

This is the friendly version of traceback … I use runserver_plus from django_extensions :

Traceback (most recent call last):
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/template/base.py”, line 875, in _resolve_lookup
current = current[bit]
TypeError: ‘Prodotto’ object is not subscriptable

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/contrib/staticfiles/handlers.py”, line 80, in call
return self.application(environ, start_response)
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/core/handlers/wsgi.py”, line 132, in call
response = self.get_response(request)
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/core/handlers/base.py”, line 140, in get_response
response = self._middleware_chain(request)
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/core/handlers/exception.py”, line 57, in inner
response = response_for_exception(request, exc)
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/core/handlers/exception.py”, line 139, in response_for_exception
response = handle_uncaught_exception(
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/core/handlers/exception.py”, line 180, in handle_uncaught_exception
return debug.technical_500_response(request, *exc_info)
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django_extensions/management/technical_response.py”, line 40, in null_technical_500_response
raise exc_value.with_traceback(tb)
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/core/handlers/exception.py”, line 55, in inner
response = get_response(request)
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/core/handlers/base.py”, line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/cms/magazzino/views.py”, line 25, in Magazzino
return render(request, ‘magazzino.html’,
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/shortcuts.py”, line 24, in render
content = loader.render_to_string(template_name, context, request, using=using)
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/template/loader.py”, line 62, in render_to_string
return template.render(context, request)
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/template/backends/django.py”, line 62, in render
return self.template.render(context)
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/template/base.py”, line 175, in render
return self._render(context)
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/template/base.py”, line 167, in _render
return self.nodelist.render(context)
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/template/base.py”, line 1000, in render
return SafeString("".join([node.render_annotated(context) for node in self]))
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/template/base.py”, line 1000, in
return SafeString("".join([node.render_annotated(context) for node in self]))
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/template/base.py”, line 958, in render_annotated
return self.render(context)
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/template/loader_tags.py”, line 157, in render
return compiled_parent._render(context)
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/template/base.py”, line 167, in _render
return self.nodelist.render(context)
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/template/base.py”, line 1000, in render
return SafeString("".join([node.render_annotated(context) for node in self]))
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/template/base.py”, line 1000, in
return SafeString("".join([node.render_annotated(context) for node in self]))
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/template/base.py”, line 958, in render_annotated
return self.render(context)
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/template/loader_tags.py”, line 63, in render
result = block.nodelist.render(context)
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/template/base.py”, line 1000, in render
return SafeString("".join([node.render_annotated(context) for node in self]))
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/template/base.py”, line 1000, in
return SafeString("".join([node.render_annotated(context) for node in self]))
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/template/base.py”, line 958, in render_annotated
return self.render(context)
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/template/defaulttags.py”, line 238, in render
nodelist.append(node.render_annotated(context))
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/template/base.py”, line 958, in render_annotated
return self.render(context)
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/template/base.py”, line 1059, in render
output = self.filter_expression.resolve(context)
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/template/base.py”, line 712, in resolve
obj = self.var.resolve(context)
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/template/base.py”, line 842, in resolve
value = self._resolve_lookup(context)
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/venv/lib/python3.10/site-packages/django/template/base.py”, line 885, in _resolve_lookup
current = getattr(current, bit)
File “/Users/mattiademarco/Desktop/schiroli_farmaceutici/cms/magazzino/models.py”, line 91, in statusColor
return color
UnboundLocalError: local variable ‘color’ referenced before assignment

I hope it can help!

That’s a different error than report earlier. Before, you said that it was referencing the variable named status. This error message is referring to color.

Same idea though - for whatever reason, total_quantity is not working out to be a value allowing for any of those chained conditions to be True.

Before that specific error, this is the last user-written code that appears to be referenced in that traceback. That’s where you want to start your search.

1 Like

There’s also this error:

Next step then is for you to examine the views where the error is being thrown.

1 Like