views:

50

answers:

1

Here is a Django model I'm using.

class Person(models.Model):
    surname = models.CharField(max_length=255, null=True, blank=True)
    first_name = models.CharField(max_length=255, null=True, blank=True)
    middle_names = models.CharField(max_length=255, null=True, blank=True)
    birth_year = WideYear(null=True, blank=True)
    birth_year_uncertain = models.BooleanField()
    death_year = WideYear(null=True, blank=True)
    death_year_uncertain = models.BooleanField()
    flourit_year = WideYear(null=True, blank=True)
    flourit_year_uncertain = models.BooleanField()
    FLOURIT_CHOICES = (
        (u'D', u'Birth and death dates'),
        (u'F', u'Flourit date'),
    )
    use_flourit = models.CharField('Date(s) to use', max_length=2, choices=FLOURIT_CHOICES)
    def __unicode__(self):
        if str(self.birth_year) == 'None':
            self.birth_year = '' 
        if str(self.death_year) == 'None':
            self.death_year = ''
        if str(self.flourit_year) == 'None':
            self.flourit_year = '' 
        if self.use_flourit == u'D':
            return '%s, %s %s (%s - %s)' % (self.surname, self.first_name, self.middle_names, self.birth_year, self.death_year)
        else:
            return '%s, %s %s (fl. %s)' % (self.surname, self.first_name, self.middle_names, self.flourit_year)

This bit of code from the model's __unicode__ method seems rather verbose:

if str(self.birth_year) == 'None':
    self.birth_year = '' 
if str(self.death_year) == 'None':
    self.death_year = ''
if str(self.flourit_year) == 'None':
    self.flourit_year = ''

Its aim is to stop the __unicode__ method from returning something like

Murdoch, Rupert (1931 - None)

and to ensure the method instead returns something like

Murdoch, Rupert (1931 - )

Is there a way to "glob" that bit of code somehow, e.g. using a wildcard so that all attributes of the self object are processed?

Something like this:

if str(self.(*)) == 'None':
   self.$1 = ''

Here, I've just used regular expression syntax to illustrate what I mean; obviously, it's not working python code. Essentially the idea is to loop through each of the attributes, checking if their str() representations are equal to 'None' and if so, setting them to ''. But it would be nice if this could be done more concisely than by setting up a for loop.

+5  A: 
for n in dir(self):
  if getattr(self, n) is None:
    setattr(self, n, '')

I'm using the normal is None idiom, assuming there's no hypersubtle motivation for that weird alternative you're using, but that's a separate issue;-)

Edit: if you're using a framework laden with VERY deep black-magic, like Django, perfectly normal Python approaches suddenly may become fraught -- as the OP seems to have indicated with a similarly-murky edit. Well, if the dark deep metaclasses of Django don't let this work (though I can't reproduce the issue as the OP reports it), there are always alternatives. In particular, since this is taking place inside a special method that SHOULDN'T alter the object (__unicode__, specifically), I recommend a simple auxiliary function (a plain good old stand-alone module-level function!):

def b(atr): return atr or u''

to be used as follows:

def __unicode__(self):
  if self.use_flourit == u'D':
    return '%s, %s %s (%s - %s)' % (
        b(self.surname), b(self.first_name), b(self.middle_names),
        b(self.birth_year), b(self.death_year)
    )
  else:
    return '%s, %s %s (fl. %s)' % (
        b(self.surname), b(self.first_name), b(self.middle_names),
        b(self.flourit_year)
    )

Note that my original answer is perfectly fine when (A) you WANT to alter self as needed (in converters such as __unicode__, __str__, __repr__, ..., you shouldn't!), AND (B) you're in a class that doesn't use REALLY deep, dark, soot-black magic (apparently Django's models superclass is breaking something absolutely fundamental such as dir, setattr, and/or getattr -- though even with that hypothesis I just can't reproduce the specific symptoms somewhat-reported by the OP).

Alex Martelli
Thanks, but that didn't work for me. I've expanded my question above to provide a bit more context. When I substituted my verbose code block with the code you suggested, the __unicode__ method just returned "(None)".
sampablokuper
The auxiliary function you suggested in your update worked, and on reflection I agree with you about altering **self**, so thank you ever so much for the advice on both fronts. I'm only an occasional Python/Django coder, so I'm still very much on the learning curve. Also, although most of the time I find Django's magic is more of a help than a hindrance, it's true that it occasionally causes me to trip up!I probably should have provided the full context before posting my question in its original form; sorry for that. I was hoping it would prove to be just be a generic Python question.
sampablokuper
@sampablockuper, NP -- of course you couldn't know about Django's magic interfering here (that's just the problem with black magic, not your fault;-). A good framework like Django does make your life easier when you're doing what it "wants" to do (and when it's well designed that will be 90%+ of the time)... the tradeoff is that it may make it harder to "deviate" from the framework's conceptions the remaining 10% or less of the time, but that's not necessarily a bad tradeoff (as you see, you're not necessarily lost when the price applies, like here;-).
Alex Martelli