5

I'm creating a property on a Django model called "address". I want address to consist of the concatenation of a number of fields I have on my model. The problem is that not all instances of this model will have values for all of these fields. So, I want to concatenate only those fields that have values.

What is the best/most Pythonic way to do this?

Here are the relevant fields from the model:

house = models.IntegerField('House Number', null=True, blank=True)
suf = models.CharField('House Number Suffix', max_length=1, null=True, blank=True)
unit = models.CharField('Address Unit', max_length=7, null=True, blank=True)
stex = models.IntegerField('Address Extention', null=True, blank=True)
stdir = models.CharField('Street Direction', max_length=254, null=True, blank=True)
stnam = models.CharField('Street Name', max_length=30, null=True, blank=True)
stdes = models.CharField('Street Designation', max_length=3, null=True, blank=True)
stdessuf = models.CharField('Street Designation Suffix',max_length=1, null=True, blank=True)

I could just do something like this:

def _get_address(self):
    return "%s %s %s %s %s %s %s %s" % (self.house, self.suf, self.unit, self.stex, self.stdir, self.stname, self.stdes, self.stdessuf)

but then there would be extra blank spaces in the result.

I could do a series of if statements and concatenate within each, but that seems ugly.

What's the best way to handle this situation?

Thanks.

3 Answers 3

4
parts = (1, 'a', 'b', 2, 'c', 'd', None, 'f')
# parts = (self.house, self.suf, self.unit, 
#           self.stex, self.stdir, self.stname, 
#           self.stdes, self.stdessuf)
' '.join(str(part) for part in parts if part is not None)
# '1 a b 2 c d e f'

You just do a list comp, and check if any value is not None, and also convert them to a string so they join properly regardless of type.

Sign up to request clarification or add additional context in comments.

7 Comments

Thanks for the 'not None' addition
@DouglasMeehan: Sure. Also if you want to save on creating a temp list every single time you call the method, you could save the fields in a list as a class attribute, since its not going to change between instances.
What's better in this situation? tuple or list?
So i would create another property which would be the list of these fields and then reference that property in the address property?
A list has a slight overhead over a tuple. But use a tuple since you aren't going to modify it at all. And ya you could create another class attribute at the bottom after the fields, then reference is in your method with self._address_fields
|
2
" ".join(filter(None, 
               [self.house, self.suf, self.unit, 
                self.stex, self.stdir, self.stname, 
                self.stdes, self.stdessuf]))

1 Comment

This breaks if the field is not a string.
2

I'd use a generator to get just the non-Falsy values, and then join them. For example:

parts = (self.house, self.suf, self.unit, self.stex, self.stdir, self.stname, self.stdes, self.stdessuf)
return " ".join(str(s) for s in parts if s is not None)

2 Comments

You need to check for None, and not a Falsey value. None is not the same as 0 which is a valid number
so in that case, I could do parts = (self.house, self.suf, self.unit, self.stex, self.stdir, self.stname, self.stdes, self.stdessuf) return " ".join(str(s) for s in parts if s is not None)?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.