Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Rest Framework foreign key serialization

I have the following models:

class Geofence(models.Model):
    id = models.IntegerField(default=0, primary_key=True)
    name = models.CharField(max_length=200, default="Geofence", blank=False)
    lat = models.DecimalField(default=0, decimal_places=6, max_digits=10, blank=False)
    long = models.DecimalField(default=0, decimal_places=6, max_digits=10, blank=False)
    radius = models.IntegerField(default=10, blank=False)

    def __str__(self):
        return "Geofence: " + str(self.name);

class Checkpoint(models.Model):
    id = models.IntegerField(default=0, primary_key=True)
    name = models.CharField(max_length=200, default="Geofence", blank=False)
    geofence = models.ForeignKey(Geofence, related_name='geofence')
    lat = models.DecimalField(default=0, decimal_places=6, max_digits=10, blank=False)
    long = models.DecimalField(default=0, decimal_places=6, max_digits=10, blank=False)
    trip_id = models.IntegerField(default=0, blank=False)
    enter_time = models.DateTimeField("Enter Time", blank=False)
    start_time = models.DateTimeField("Start Time", blank = True, null=True)
    stop_time = models.DateTimeField("Stop Time", blank= True, null = True)

and their respective serializers:

class GeofenceSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(min_value=0)
    name = serializers.CharField()
    lat = serializers.DecimalField(max_digits=10, decimal_places=6, coerce_to_string=False)
    long = serializers.DecimalField(max_digits=10, decimal_places=6, coerce_to_string=False)
    radius = serializers.IntegerField(min_value=0)
    class Meta:
        model = Geofence
        fields = ('id', 'name','lat', 'long', 'radius')

    def create(self, valid_data):
        return Geofence.objects.create(**valid_data)

    def update(self, instance, valid_data):
        instance.id = valid_data.get('id', instance.id)
        instance.name = valid_data.get('name', instance.name)
        instance.name = valid_data.get('lat', instance.lat)
        instance.long = valid_data.get('long', instance.long)
        instance.radius = valid_data.get('radius', instance.radius)
        instance.save()



class CheckpointSerializer(serializers.ModelSerializer):
    lat = serializers.DecimalField(max_digits=10, decimal_places=6, coerce_to_string=False)
    long = serializers.DecimalField(max_digits=10, decimal_places=6, coerce_to_string=False)
    enter_time = serializers.DateTimeField()
    start_time =serializers.DateTimeField()
    geofence = serializers.SlugRelatedField(many=False, slug_field="id", read_only=True)
    class Meta:
        model = Checkpoint
        fields = ('trip_id', 'geofence', 'start_time', 'stop_time', 'lat', 'long', 'enter_time')

I am taking datetimes from a slider and making an ajax call to get the relevant data. The server responds with a 500 error. Specifically, the error "KeyError: geofence"

Here is the view that is called:

class ResultsView(APIView):
    model = Checkpoint
    serializer_class = CheckpointSerializer
    def get(self, request, start, end):
        begin_date = parse_datetime(request.GET["start"]) 
        end_date = parse_datetime(request.GET["end"])
        ids = Checkpoint.objects.filter(start_time__range=(begin_date,end_date)).filter(stop_time__range=(begin_date,end_date)).distinct().values('trip_id', 'lat', 'long', 'enter_time')
        serializer = CheckpointSerializer(ids, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        request.data["id"] = uuid.uuid4().int & (1<<8)-1
        serializer = CheckpointSerializer(data= request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.error)

and angular call:

$http.get("http://127.0.0.1:8000/traffic/get/?end=" + $scope.endDateTime + "&format=json&search=Search&start=" + $scope.startDateTime)
  .then(function(response) {
     console.log("Response: " + response.data)
       $scope.data = response.data;
   });

I believe the issue is the foreign key in the serializer:

geofence = serializers.SlugRelatedField(many=False, slug_field="id", read_only=True)

Is this the correct way to serialize a foreign key in django rest framework? If not, would someone provide an example?

like image 506
Hardrock302 Avatar asked Nov 28 '22 06:11

Hardrock302


2 Answers

For this particular issue, I solved it by using the source argument in a character field to represent a foreign key as opposed to a related field. The correct serializer entry in this case is:

geofence = serializers.CharField(source='geofence.id', read_only=True)

class Meta:
    model = Checkpoint
    fields = ('geofence', 'start_time', 'lat', 'long', 'enter_time')

I used this in the Checkpoint table as a checkpoint is a geofence instead of incorrectly putting the foreign key in the geofence table in the original post. The field name is simply listed in the class meta. The class meta being necessary because the serializer is a model serializer.

like image 39
Hardrock302 Avatar answered Dec 04 '22 08:12

Hardrock302


Do you mean this? Specifying nested serialization

There is an simple example:

class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        depth = 1 # You need only add this sentence.

The result is something like this:

[
  {
    "id": 1,
    "priority": 10,
    "role": {
      "id": 1,
      "department": "researcher"
    }
  }
]

However, you can get all the fields of the ForeignKey. I don't know how to get some of the fields of the ForeignKey.

like image 110
Xing Zhang Avatar answered Dec 04 '22 10:12

Xing Zhang