0
votes

I have an application that has a Company, and this company can have 0 or multiple addresses. Companies are not the only 'models' that could have addresses. To achieve this, I use ContentTypes.

models.py

class Company(models.Model):
''' models a company in the system. '''

    number = models.CharField(_('Number'), unique=True, max_length=20)
    name = models.CharField(_('Name'), max_length=100)
    active = models.BooleanField(_('Active'), default=True)

    def _get_addresses(self):
        '''
        '''
        contentType = ContentType.objects.get(
            model=self.__class__.__name__.lower()
        )
        try:
            addresses = Address.objects.get(
                actor_type=contentType, actor_id=self.id
            )
        except Address.DoesNotExist:
            addresses = []
        return addresses
    addresses = property(_get_addresses)

class Address(Auditable):
    ''' models an address '''

    actor_type = models.ForeignKey(ContentType)
    actor_id = models.PositiveIntegerField()
    actor_object = fields.GenericForeignKey('actor_type', 'actor_id')
    _type = models.CharField(
        _('Address Type'), 
        max_length=10,
        choices=sorted(TYPES.items())
    )
    active = models.BooleanField(default=True)
    address1 = models.CharField(_('Address 1'), max_length=50)
    address2 = models.CharField(
        _('Address 2'),
        max_length=50,
...

This way, I could also have a Profile model and I could link multiple addresses to a Profile. However, my problem comes when I tried to implement the Serializers.

Serializers.py

class AddressSerializer(serializers.ModelSerializer):
    class Meta:
        model = Address
        fields = (
            '_type',
            'address1',
            'address2',
            'address3',
            'country',
            'state',
            'city'
        )

class CompanySerializer(serializers.ModelSerializer):

    addresses = AddressSerializer(required=False, many=True)

    class Meta:
        model = Company
        fields = (
            'number',
            'name',
            'addresses'
        )

This implementation gives me this error. It says that it cannot iterate through Address model (which makes sense), but I'm not sure how to make my addresses iterable.

I would need to perform CRUD operations not only on the Company, but also on the nested Addresses.

Any suggestions/ideas on how to go about this?

1
There is no direct relationship between company and address, is there?zaidfazil
@FazilZaid there is no relationship from Company to Address (aside from the addresses property; just added it to the models.py), but you can get a relationship from Address to Company, or to any other model.m4rk4l
But Generic foreign key is not accessible as a field for you to do the serialization...zaidfazil
well, if you had to create a company that could potentially have multiple addresses, how would you do it?m4rk4l
I would add a ForeignKey in the Address table towards Company table with required fields...zaidfazil

1 Answers

1
votes

The following database schema is just a suggestion for the scenario prevailed.

class Details(models.Model):
    official_name = models.CharField(....)
    is_company = models.BooleanField(default=False)
    #something like that....

class Address(models.Model):
    owner = models.ForeignKey(Details, related_name='addresses')
    is_company = models.BooleanField(default=False)
    building_name = .....
    building_no = ......
    locality = ......
    #some other fields.....

class Company(models.Model):
    details = models.OneToOneField(Details, related_name='company')
    name = models.CharField(...)
    number = .....
    is_active = ........

class Profile(models.Model):
    details = models.OneToOneField(Details, related_name='profile')
    name = models.CharField(....)
    .........

Here, each Company table and Profile table has a one to one relationship with a Details table. The Details table is related to the Address table with a Foreign key in it. So, each Company or Profile can have multiple addresses through the Details table.

So, the queries would be like,

For accessing addresses from the Company or Profile instances,

company.details.addresses.all()#or
profile.details.addresses.all()

For reverse queries are simple as the tables contains the respective fields in them, for a given address the owner would be, address.owner.profile or address.owner.company which could be determined by a flag in the respective tables.

I know, designing the database like this is somewhat tiring. But, this does helps in serialization of the data into a better format.

Serializers can be as follows,

class DetailsSerializer(ModelSerializer):
    addresses = AddressSerializer(source='addresses', many=True)
    class Meta:
        model = Details
        fields = ('addresses',)

class AddressSerializer(ModelSerializer):
    class Meta:
        model = Address
        fields = '__all__'

class CompanySerializer(ModelSerializer):
    details = DetailsSerializer()
    class Meta:
        model = Company
        fields = ('details', .........)

class ProfileSerializer(ModelSerializer):
    details = DetailsSerializer()
    class Meta:
        model = Profile
        fields = ('details', .........)