views:

183

answers:

3

Hello,

I'm trying to create a product code (in the admin) by combining elements from two other fields - one of which is a ManyToManyField. I'd like to iterate through that field to find out if a specific product option has been chosen, and append a variation of it to that non-editable product code, like so:

class ShirtColorClass(models.Model):
    shirtcolor = models.CharField(_('Shirt Color'), unique=True, max_length=40)
    def __unicode__(self):
        return self.shirtcolor

class ShirtClass(models.Model):
    shirtmodel = models.CharField(_('Model of Shirt'), max_length=40)
    shirtclr = models.ManyToManyField(_(ShirtColorClass, verbose_name='Shirt Color'))
    shirtcode = models.CharField(_('Code for the shirt'), max_length=80, editable=False)
    #...10 more fields...
    def __unicode__(self):
        return self.shirtmodel
    def save(self):
        for item in self.shirtclr: #these are the lines I'm not sure how to do
            if 'Blue' in self.shirtclr:
                self.shirtcode = u'%s%s' % ('B', self.shirtmodel)
            else:
                self.shirtcode = self.shirtmodel
            super(ShirtClass,self).save()

At the moment I'm getting a ManyRelatedManager not Iterable message, so I know I'm doing something wrong, but I don't know what... I apologize in advance for this being a stupid newbie question. Thank you.

+5  A: 

Try calling .all() on it.

Ignacio Vazquez-Abrams
...so something like this: def save(self): for item in self.shirtclr.all(): if item == 'Blue': self.shirtcode = u'%s%s' % ('B', self.shirtmodel) else: self.shirtcode = self.shirtmodel super(ShirtClass,self).save()I can't quite get that to work...ShirtClass not iterable is the error. What am I doing wrong? Thank you once again.
bkev
I think we need to step back and find out what you're actually trying to accomplish here.
Ignacio Vazquez-Abrams
Thank you so much for your help. I'm trying to save a third field by concatenating the components of the first two...the only complication is that one of the first two is a ManyToManyField and I don't know the proper way to access its contents in this instance. Looking at what I typed at the top, I don't think I need a for loop there...when I've used Python before, "in" has done the work for me when looking through a list. However, "if 'Blue' in self.shirtcode.all()" doesn't seem to work for me. I keep thinking this shouldn't be a difficult thing to accomplish...but I'm missing something...
bkev
Perhaps instead of making it a real field you should make it a property. http://www.djangoproject.com/documentation/models/properties/ http://www.b-list.org/weblog/2006/aug/18/django-tips-using-properties-models-and-managers/
Ignacio Vazquez-Abrams
+1  A: 

call filter():

def save(self):
    if self.pk!=None:
        if self.shirtclr.filter(shirtcolor='Blue'):
            self.shirtcode = u'%s%s' % ('B', self.shirtmodel)
        else:
            self.shirtcode = self.shirtmodel
    else:
        self.shirtcode = ''

you can avoid self.shirtcode = '' by adding default='' into

shirtcode = models.CharField(_('Code for the shirt'), max_length=80, editable=False, default='')
Antony Hatchkins
did you try this?
Antony Hatchkins
Yes (and thank you for your answer...sorry I couldn't get back to you right away). If there was no existing instance, I got a "'ShirtClass' instance needs to have a primary key value before a many-to-many relationship can be used" error. If there was one, the Post would complete, but shirtcode would equal shirtmodel no matter what color I chose. Any ideas?
bkev
As for the exception - corrected the answer, should work now. As for the shirtcode being always equal to shirtmodel, are you sure it is exactly `'Blue'`, not for example `'blue'` or `'blue '`
Antony Hatchkins
A: 

Thank you gentlemen for both your answers. I merged both of your answers into one...a property with a filter like so:

 def _get_blue_shirts(self):
  if self.shirtclr.filter(shirtcolor='Blue'):
   return '%s%s' % ('B', self.shirtmodel)
  else:
   return self.shirtmodel
 blue_shirts=property(_get_blue_shirts)

While this approach definitely works, I can see issues with it as I have written it. First, I would like to search in the admin with, for example, "B13A" as a shirt model and have it understand that what I mean is a "13A" shirt available with Blue as one of its colors. Since the ModelAdmin.search_fields seems to need to resolve to an actual field, this approach doesn't work in this regard (correct me if I'm wrong there). The other concern I have is the property seems very SQL-heavy...executing a separate select for each row (whereas a dedicated column would just need an overall select...again, correct me if I'm wrong). Any ideas as to how I might go about addressing these concerns? Perhaps another way I could go about it?

PS. Antony...I tried the revised overridden save() and still got the "'ShirtClass' instance needs to have a primary key value before a many-to-many relationship can be used" error. Am I doing something wrong here?

Many, Many, Many thanks to all, -bkev

bkev