2

I have two model like this with following fields:

Profile: 
    -user(OTO Relation to User)
    -address(OTO to Address)
    -bio
    -gender
    ...
Address: 
    -postal_code
    -phone_number
    -zip_code

I Also I have this list of fields name:

 my_list = ["bio","gender","address.postal_code","address.phone_number", "address.zip_code"]

And finally I want to I create this @property:

@property
def is_complete_profile(self):
    ''' Checks if all the fields have been filled '''
    if self.pk:
        for field_name in my_list:
            value = getattr(self,field_name)
            if not value:
                return False
        return True
    else:
        return False

But for related objects this isn't the correct way and I got this error:

'Profile' object has no attribute 'address.postal_code'

How Can I use this list for get value of field of Profile objects and related object values?

Notice:

I could solve this problem by using eval function, but because of this and this post, I preferred to throw this solution away.

snakecharmerb
  • 47,570
  • 11
  • 100
  • 153
rahnama7m
  • 865
  • 10
  • 38

2 Answers2

2

Rather than having Profile nose around in its peers' internals, I would give each class involved an is_complete property (or method) which determines if the instance is complete, and have Profile.is_complete_profile access those properties to determine if the profile is totally complete.

Something like this (untested)

class Address:

    def is_complete(self):
        fields = ["postal_code", "phone_number", "zip_code"]
        for field in fields:
            if not getattr(self, field):
                return False
        return True

class Profile:

    def is_complete(self):
        fields = ["bio","gender"]
        for field in fields:
            if not getattr(self, field):
                return False
        return True

    @property
    def is_complete_profile(self):
        ''' Checks if all the fields have been filled '''
        if self.pk:
            return self.is_complete() and self.address.is_complete()
        return False

This way Profile doesn't need to change if the names of Address's fields change, and only minimal changes are required if additional objects get added to the notion of "completeness".

snakecharmerb
  • 47,570
  • 11
  • 100
  • 153
1

You are getting this error because your Profile object really does not have an address.postal_code attribute. It has address attribute and that address has an postal_code attribute.

You can accomplish this with a simple trick:

@property
def is_complete_profile(self):
    ''' Checks if all the fields have been filled '''
    if self.pk:
        for field_name in my_list:
            if '.' in field_name:
                value = getattr(getattr(self, field_name.split('.')[0]), field_name.split('.')[1])
            else:
                value = getattr(self,field_name)
            if not value:
                return False
        return True
    else:
        return False
Pedram Parsian
  • 3,750
  • 3
  • 19
  • 34
  • Nice answer @pedram-parsian . I did vote to your answer. But I think that answer of snakecharmerb is more better.Excuse me for not being able to accept both answers. – rahnama7m Nov 13 '19 at 18:16