0

I'm advancing with the web app I asked about earlier.

Currently, my models.py is

from django.db import models
from unittest.util import _MAX_LENGTH

class Alimento(models.Model):
    INTOLERANCIAS = (
        ('00', 'Ninguna'),
        ('GL', 'Gluten'),
        ('CR', 'Crustáceos'),
        ('HU', 'Huevos'),
        ('FS', 'Frutos Secos'),
        ('AP', 'Apio'),
        ('MO', 'Mostaza'),
        ('SE', 'Sésamo'),
        ('PE', 'Pescado'),
        ('CA', 'Cacahuetes'),
        ('SO', 'Sulfitos'),
        ('SJ', 'Soja'),
        ('LA', 'Lácteos'),
        ('AL', 'Altramuz'),
        ('ML', 'Moluscos'),
        ('CA', 'Cacao'),


    )
    nombre = models.CharField(max_length=60)
    intolerancia = models.CharField(max_length=2, choices=INTOLERANCIAS)

    def __str__(self):
        return self.nombre


class Receta(models.Model):
    nombre = models.CharField(max_length=100)
    raciones = models.IntegerField(default=1)
    preparacion = models.TextField(default='')
    consejos = models.TextField(blank=True)
    ingredientes = models.ManyToManyField(Alimento, through='Ingrediente', related_name='ingredientes')

    def __str__(self):
        return self.nombre

    def getIntolerancias(self):
        ing = self.ingredientes.all()
        intolerancias = []
        for i in ing:
            alimentos = i.alimento.all()
            for a in alimentos:
                intolerancias.append(a.get_intolerancia_display()) 

        return intolerancias



class Ingrediente(models.Model):
    receta = models.ForeignKey('recetas.Receta', on_delete=models.CASCADE)
    alimento = models.ManyToManyField(Alimento)
    cantidad = models.FloatField(default=0)
    descripcion = models.CharField(max_length=60, blank=True)

    def __str__(self):
        return self.alimento.__str__()

the method getIntolerancias is supposed to list the food intolerances related to each of the ingredients of a given recipe (Receta). To do that, I try to get the queryset of ingredients (Ingrediente) with ing = self.ingredientes, but when I try it on shell I get this error message

Traceback (most recent call last):   File "/usr/lib/python3.5/code.py", line 91, in runcode
    exec(code, self.locals)   File "<console>", line 1, in <module>   File "/usr/local/lib/python3.5/dist-packages/django/db/models/fields/related_descriptors.py", line 476, in __get__
    return self.related_manager_cls(instance)   File "/usr/local/lib/python3.5/dist-packages/django/db/models/fields/related_descriptors.py", line 758, in __init__
    self.target_field_name = rel.field.m2m_reverse_field_name()   File "/usr/local/lib/python3.5/dist-packages/django/utils/functional.py", line 15, in _curried
    return _curried_func(*(args + moreargs), **dict(kwargs, **morekwargs))   File "/usr/local/lib/python3.5/dist-packages/django/db/models/fields/related.py", line 1504, in _get_m2m_reverse_attr
    return getattr(self, cache_attr) AttributeError: 'ManyToManyField' object has no attribute '_m2m_reverse_name_cache'

I've searched for the error, but the answers I've found don't seem to have what I need (I may just don't understand enough to see it does?)

UPDATE

When I run this on the shell I do

g = Receta.objects.get(nombre = 'Gazpacho')
g.getIntolerancias()

I get an error

intolerancias.append(a.get_intolerancia_display()) AttributeError: 'Ingrediente' object has no attribute 'get_intolerancia_display'

However, if I iterate and get the first element of g.ingredientes.all() and call get_intolerancia_display() it does work OK

a = g.ingredientes.all().first()
a.get_intolerancia_display()
'Gluten'
Community
  • 1
  • 1
Frank
  • 2,777
  • 5
  • 18
  • 30

1 Answers1

1

Update after comments:

Documentation about Many-to-many relation

def get_intolerancias(self):
        alimentos = self.ingredientes.all() # Give us all alimento of a recetta
        intolerancias = []
        for a in alimentos:
            intolerancias.append(a.get_intolerancia_display())            
        return intolerancias
Wilfried
  • 1,623
  • 1
  • 12
  • 19
  • I just tried on shell, with zero success :S AttributeError: 'ManyToManyField' object has no attribute '_m2m_reverse_name_cache' – Frank Mar 22 '17 at 16:50
  • I update my answer. You need to add related_name in your field ingredientes – Wilfried Mar 22 '17 at 17:09
  • apparently, I also had to change alimento = models.ManyToManyField(Alimento) to alimento = models.ForeignKey('recetas.Alimento', related_name='alimento', on_delete=models.CASCADE) for it to allow the migration. However, I still get `AttributeError: 'RelatedManager' object has no attribute 'get_intolerancia_display'` when trying to use the getIntolerancias() method in Shell – Frank Mar 22 '17 at 17:21
  • That's normal because i.alimento is a RelateManager object. Not an Alimento object model. For ingeredinetes you can have many alimento. I update my answer – Wilfried Mar 22 '17 at 21:33
  • I've done those changes (and updated the method in my question) and when tried on shell I get AttributeError: 'Ingrediente' object has no attribute 'get_intolerancia_display' for the line intolerancias.append(a.get_intolerancia_display()) – Frank Mar 22 '17 at 22:19
  • I think there is an problem in your model relation. In Receta ingredientes need to be related to Ingredientes model, right ? not Alimento ? I update my answer. Update your model – Wilfried Mar 22 '17 at 22:33
  • I updated the question with the new model and the results of my tests. Not working yet :s – Frank Mar 23 '17 at 11:02
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/138826/discussion-between-wilfried-and-frank). – Wilfried Mar 23 '17 at 12:47