Tuesday, February 21, 2017

Flattening model relationships (in APIs)

I'm using DRF for an API. My problem is that I defined my postal address like this (breaking it up into City, State, Country):

class Country(models.Model):    
    class Meta:
        db_table = 'countries'

    name = models.TextField()
    code = models.TextField(unique=True)

class State(models.Model):    
    class Meta:
        db_table = 'states'

    name = models.TextField()
    code = models.TextField(unique=True)
    country = models.ForeignKey('Country', on_delete=models.CASCADE)


class City(models.Model):    
    class Meta:
        db_table = 'cities'

    name = models.TextField()
    code = models.TextField(unique=True)
    state = models.ForeignKey('State', on_delete=models.CASCADE)

class Address(models.Model):
    class Meta:
        db_table = 'addresses'
    
    building_no = models.TextField()
    street = models.TextField(null=True)
    locality = models.TextField(null=True)
    landmark = models.TextField(null=True)
    pincode = models.TextField(null=True)
    latitude = models.DecimalField(max_digits=9, decimal_places=6, null=True)
    longitude = models.DecimalField(max_digits=9, decimal_places=6, null=True)
    city = models.ForeignKey('City', on_delete=models.CASCADE)

Now, in my system, a venue has an address, and so the serializes are defined like this:

class VenueSerializer(serializers.ModelSerializer):
    address = AddressSerializer()
    offerings = OfferingSerializer(many=True)

    class Meta:
        model = Venue
        fields = ['id', 'name', 'price_per_day', 'status', 'offerings', 'address', 'photos']

which leads us to:

class AddressSerializer(serializers.ModelSerializer):
    city = CitySerializer()

    class Meta:
        model = Address
        fields = ['id', 'building_no', 'street', 'locality', 'landmark', 'pincode', 'latitude', 'longitude', 'city']

which leads us to:

class CitySerializer(serializers.ModelSerializer):
    state = StateSerializer()

    class Meta:
        model = City
        fields = ['id', 'name', 'code', 'state']

which leads us to:

class StateSerializer(serializers.ModelSerializer):
    country = CountrySerializer()

    class Meta:
        model = State
        fields = ['id', 'name', 'code', 'country']

which finally leads to:

class CountrySerializer(serializers.ModelSerializer):
    class Meta:
        model = Country
        fields = ['id', 'name', 'code']

and when this gets serialized, the address is given in the following format:

 "address": {
      "id": 2,
      "building_no": "11",
      "street": "Another Street",
      "locality": "",
      "landmark": "Fortis Hospital",
      "pincode": "201003",
      "latitude": "28.632778",
      "longitude": "77.219722",
      "city": {
        "id": 1,
        "name": "Delhi",
        "code": "DEL",
        "state": {
          "id": 1,
          "name": "Delhi",
          "code": "DEL",
          "country": {
            "id": 1,
            "name": "India",
            "code": "IN"
          }
        }
      }
    }

So there's a hell lot of nesting from city to state to country. If the relationship chain was even deeper, there would be even more nesting, which I feel isn't great for API consumers. What is the best practice here to put state and country at the same level as the city? I think this will also complicate the logic while POSTing data, so I'm interested in knowing about that as well.

I'm sorry if there is too much code, but I couldn't think of a better way to convey the situation than actually post everything.


Regards,
Ankush Thakur

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/CALX%3DrK%2Bgbbro%2BkFYsq%3DFDCSu2kw6KRmsfKRamKLA%2Bisrgj%3DboQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

No comments:

Post a Comment