Search code examples
djangoangularjsrestdjango-rest-frameworkrestangular

Restangular, Django REST and relations


I'm using Django REST Framework for modelling a REST API that uses a lot of model relations.

What's an easy and good way to resolve those relations at the frontend level using AngularJS and Restangular?

Models

This is how part of my models look like:

class Country( Model ):
  name = CharField( max_length = 256 )

class City( Model ):
  name = CharField( max_length = 256 )
  postal_code = CharField( max_length = 16 )

  country = ForeignKey( "Country" )

class Customer( Model ):
  first_name = CharField( max_length = 256 )
  last_name = CharField( max_length = 256 )

  city = ForeignKey( "City" )

Fetching the data

The following JavaScript code shows how I load the data: (I actually use the promises returned by all(), but $object is shorter for explaining this)

$scope.countries = [];
$scope.cities = [];
$scope.customers = [];

Restangular.all( "countries" ).getList().$object;
Restangular.all( "cities" ).getList().$object;
Restangular.all( "customers" ).getList().$object;

Here's an example of a cities reponse: (all, without exception, models contain an id field)

[{"id": 1, "name": "Bocholt", "postal_code": "46397", "country": 1}]

Displaying the data

And finally the AngularJS part for displaying the data; the code you see here is how I'd like to use it:

<table>
  <tbody>
    <tr ng-repeat="customer in customers">
      <td>{{ customer.first_name }}</td>
      <td>{{ customer.last_name }}</td>
      <td>{{ cities[customer.city].name }}</td>
      <td>{{ countries[cities[customer.city].country].name }}</td>
    </tr>
  </tbody>
</table>

Admittedly the nested statement looks a little bit ugly, but considering the fact that the original data stays intact, I'm fine with doing it like that.


Unfortunately the code does (of course) not work. What's a good way to solve such kind of relations?


Clue: I'm willing to change my way of doing things at any of the involved frameworks/programs (Django, Django REST, AngularJS, Restangular etc.).


Solution

  • I believe the best way to do this is to create nested serailizers. You'll have to switch out the serializer on posts, but on list and retrieves a serializer like this would work.

    class CountrySerializer(serializer.ModelSerializer):
        class Meta:
            model = Country
    
    
    class CitySerializer(serializer.ModelSerializer):
        country = CountrySerializer()
        class Meta:
            model = City
    
    class CustomerSerializer(serializer.ModelSerializer):
        city = CitySerializer()
        class Meta:
            model = Customer
    
    class CustomerViewSet(viewsets.ModelViewSet):
        model = Customer
        serializer_class = CustomerSerializer
        queryset = Customer.objects.all()
    

    And then your Restangular just has to hit the api and the object is properly nested

    Restangular.all('costumers').one(1).get().then(function(response) {
        $scope.costumer = response; 
    })