Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django rest framework - create a resource that has foreign keys with a single API call

Tags:

rest

django

api

I'm having trouble creating an "Estimate" resource. Basically, what I'm trying to achieve is to make a single API call to create an "Estimate" instance, which has 3 foreign keys, and would prefer to use ModelViewSet to take advantage of all methods that comes with using it(POST, GET, PUT, DELETE, PATCH).

example :

Make a single POST call with the following data : {user: , property: , estimate_type:, message: "test message"} /api/estimates/

I managed to configure the API to retrieve all the details that I need, with exception of the "User" object details, instead I only get the URL, but I guess that's ok, since I can fetch the User details on a separate call.

I'm a bit confused and like to understand what's the correct approach to achieve creating the "Estimate" instance with a single call. Should I be overriding the save method of "Estimate" class?

All suggestions are greatly appreciated.

Django==1.7.6 djangorestframework==3.1.0

These are my models :

class Property(models.Model):
    user         = models.ForeignKey(User)
    address      = models.CharField(max_length=100)

def __str__(self):
    return self.address


class EstimateType(models.Model):
    name          = models.CharField(max_length=100)

def __str__(self):
    return self.name

class Estimate(models.Model):
    user          = models.ForeignKey(User)
    property      = models.ForeignKey(Property)
    estimate_type = models.ForeignKey(EstimateType)
    message       = models.TextField(max_length=144)

def __str__(self):
    return "{} {}".format(self.user.username, self.property.address1)

These are the serializers :

class UserSerializer(serializers.HyperlinkedModelSerializer):

class Meta:
    model = User
    fields = ('pk','username', 'email','first_name', 'last_name', 'is_staff')

class PropertySerializer(serializers.ModelSerializer):
    user = UserSerializer()

    class Meta:
        model = Property
        fields = ('pk','address','user')

class EstimateTypeSerializer(serializers.ModelSerializer):

    class Meta:
        model = EstimateType
        fields = ('pk', 'name')

class EstimateSerializer(serializers.HyperlinkedModelSerializer):
    property = PropertySerializer()
    service  = EstimateTypeSerializer()

class Meta:
    model = Estimate
    fields = ('pk','user','property','service', 'message')

The ViewSets:

class UserViewSet(viewsets.ModelViewSet):
    queryset         = User.objects.all()
    serializer_class = UserSerializer

class PropertyViewSet(viewsets.ModelViewSet):
    queryset         = Property.objects.all()
    serializer_class = PropertySerializer

class EstimateTypeViewSet(viewsets.ModelViewSet):
    queryset         = EstimateType.objects.all()
    serializer_class = EstimateTypeSerializer

class EstimateViewSet(viewsets.ModelViewSet):

    serializer_class = EstimateSerializer

    def get_queryset(self):
        queryset = Estimate.objects.filter(user=self.request.user)
        return queryset

Sending GET request to /api/estimate/

Retrieves the following :

    [
  {
    "pk": 3,
    "user": "http://localhost:8000/users/2/",
    "property": {
      "pk": 3,
      "address": “123 Fake street",
      "user": {
        "pk": 2,
        "username": “admin”,
        "email": “[email protected]”,
        "first_name": “Foo”,
        "last_name": “Bar”,
        "is_staff": true
      }
    },
    “estimate_type”: {
      "pk": 1,
      "name": “basic”
    },
    "message": "Lorem Ipsum is simply dummy text of the printing and typesetting \n”
  }
]
like image 780
Nerses Avatar asked Mar 18 '15 02:03

Nerses


1 Answers

To create a new Estimate linked to other existing records you would only need to send an object like this, with only the primary keys identifying the related objects:

{
    "user": <user pk>,
    "property": <property pk>,
    "estimate_type": <estimate type pk>,
    "message": "foo bar"
}

Writing to nested serializers - as you do - was not supported by restframework 2.x.

Have a look at how to create a writable RelatedField class: http://www.django-rest-framework.org/api-guide/relations/#custom-relational-fields

like image 174
djangonaut Avatar answered Nov 19 '22 12:11

djangonaut