How to use one Model Class values in another in Django?

Asked

Viewed 987 times

4

Talk guys, I haven’t found a north or how to research on, so I’m going to go to the O.R..

I have the following in my models.py, Ingredient and Product:

class Ingrediente(models.Model):
    produtor = models.ForeignKey('auth.User', on_delete=models.CASCADE, default=10)
    nome = models.CharField(max_length=200)
    descricao = models.TextField()
    quantidade = models.DecimalField(max_digits=10, decimal_places=3)
    custo = models.DecimalField(max_digits=10, decimal_places=2)

and

class Produto(models.Model):
    nome = models.CharField(max_length=200)
    custo_produto = #aqui minha dúvida
    porcentagem_lucro = models.DecimalField(max_digits=10, decimal_places=2)
    valor_venda = models.DecimalField(max_digits=10, decimal_places=2)
    descricao = models.TextField()
    ingredientes = models.ManyToManyField(Ingrediente)

I wonder how I can make that custo_produto be a sum of custo of the instances of Ingrediente that are associated with the Produto.

Do you understand? The sum of the cost of the ingredients is the cost of the product.

2 answers

7


This is a legal case to use a property - when for the code that will use its instances, there will be simply reading the attribute, but in the class, a method is executed automatically.

Note that the main difference is that in this case, the custo_produto will exist as object attribute, but will not exist in the table corresponding to that model in the database - only the code on the Python side will calculate that value:

You can do it with several lines, it’s more readable:

class Produto(models.Model):
    nome = models.CharField(max_length=200)
    porcentagem_lucro = models.DecimalField(max_digits=10, decimal_places=2)
    valor_venda = models.DecimalField(max_digits=10, decimal_places=2)
    descricao = models.TextField()
    ingredientes = models.ManyToManyField(Ingrediente)

    @property
    def custo_produto(self):
          total = 0
          for ingrediente in self.ingredientes.all():
               total += ingredientes.custo
           return total

How he the .custo_produto will not be part of fields, it is better to put your statement last, not to interfere in the statement of Fields - but this is more aesthetic than anything else.

You can also use a more advanced Python syntax, with Generator Expression, sum and lambda, to do the same thing in a single line:

class Produto(models.Model):
    nome = models.CharField(max_length=200)
    custo_produto = property(lambda self: sum(ingr.custo for ingr in self.ingredientes.all() ))
    porcentagem_lucro = models.DecimalField(max_digits=10, decimal_places=2)
    valor_venda = models.DecimalField(max_digits=10, decimal_places=2)
    descricao = models.TextField()
    ingredientes = models.ManyToManyField(Ingrediente)

I explained more about properties in another recent response - there, without being Django-specific classes: Definition and use of @Property

  • Thanks for your help, but I still had problems. I tested both solutions by copying the code to make sure it was not wrong, and I got an error: "'Manyrelatedmanager' Object is not iterable". Remember that in my template I used {{ products.custo_product ?

  • the use between two keys is to use in a template - is another language programming - here we are talking about the Python part. Are you trying to see the cost_product of an instance (a specific product), or direct from the class? In the class will give error. Let me take a look at instances if you need something else. (Django is usually "pythonico", but sometimes they screw up)

  • I understand jsbueno, the idea is to play this value for the Django template, so I thought of this syntax because it is the same as I use for the other attributes of the Product class. On the page specifically I pull the details of each instance, as its name, description, and now would also have its cost_product

  • Ready - I found the problem - the Manytmany field is not eternal in itself - it is a "Queryset" of Django - need to call the method .all() in it so that it returns an iterable for all related objects. I changed the code to do this.

  • Inside the template you can also use direct now: {{ produto.custo_produto }}

  • I’ll test it right now!

  • That was perfect boss, only two more things to say: 1 - no for, the correct is "ingredients" with "s", and not without the "s" (tested and confirmed hahaha). 2 - If you can suggest me where to learn more about this and how you came to this solution, thank you, I’m reading your other answer (which Oce linked, about properties). Thank you! Working!

  • 1

    The answer I called about "Property" is a good start. The rest is programming practice even - the ideal is to have enough resourcefulness to arrive at the first solution without having any doubt. The second solution is more specific to Python.

  • 1

    As for variable no for, the variable name is created on its own for so it is ingrediente same - who writes the for which gives the name. - there, if instead of a Python command it was a phrase in English, the delay would be para [cada] ingrediente em ingredientes: (and not para [cada] ingredientes em ingredientes) Could be a, x, paralelepipedo - would work the same way.

Show 4 more comments

0

Hello, From what I understand, you’ll have to make one forloop more or less thus :

Note: The code is not correct

class Ingrediente() # a classe

    custoTotal = 0
    for i in Ingrediente # voce chama a classe, ela tem que contar ou use .COUNT
         custoTotal= custoTotal+Ingrediente.custo #especifica o nome da variavel 
    endfor
return custototal # retorna depois do loop com o total

class Produto(models.Model):
nome = models.CharField(max_length=200)
custo_produto = custototal #os totais somados
...

Links: https://stackoverflow.com/questions/1107737/numeric-for-loop-in-django-templates

  • negative for being in pseudocode, the reference to the link tambḿ speaks of loops in templtes, which is not the case, and you repeated the wrong identation of the edition of the original question. although the main idea is correct - the lack of language specificities, nonexistent keywords, senseless use of "class", I have to warn other readers who are learning Python.

  • Thanks for the tip, I tried to answer as soon as possible. Next time I will ask so you can make a more elaborate reply.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.