6

In a Django-REST-framework project I tried to use the nested relationship and got a "non_field_errors" in the browsable API web view.

The code is from this part of the documentation: http://www.django-rest-framework.org/api-guide/relations#nested-relationships

models.py:

from django.db import models

class Album(models.Model):
    album_name = models.CharField(max_length=100)
    artist = models.CharField(max_length=100)

class Track(models.Model):
    album = models.ForeignKey(Album, related_name='tracks')
    order = models.IntegerField()
    title = models.CharField(max_length=100)
    #duration = models.IntegerField()

    class Meta:
        unique_together = ('album', 'order')
        ordering = ('order',)

    def __unicode__(self):
        return '%d: %s' % (self.order, self.title)

serializers.py:

from rest_framework import serializers
from myapp.models import Album, Track

class TrackSerializer(serializers.ModelSerializer):
    class Meta:
        model = Track
        fields = ('order', 'title')

class AlbumSerializer(serializers.ModelSerializer):
    tracks = TrackSerializer(many=True)

    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')

ERROR (at ../albums):

The Track input field is marked red with the error message: non_field_errors.

Clicking the OPTIONS button reveals the actual&correct data structure:

Tracks nested with their appropriate propertie

The raw data input of the browsable browser view shows:

{
    "album_name": "", 
    "artist": "", 
    "tracks": null
}

Posting some valid raw-data actually works. But it'd be nicer if the web interface form would work as well. Especially since I'm wondering if there's something funny going on anyway.

Thank you in advance!

2 Answers 2

3

I have experienced this issue as well. One way to get rid of the error is to use:

class AlbumSerializer(serializers.ModelSerializer):
    tracks = serializers.RelatedField(many=True)

    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')

However, this removes the nested track fields and displays only a string representation of the tracks.

Edit: I figured it out. What you want is this:

class AlbumSerializer(serializers.ModelSerializer):

    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')
        read_only_fields = ('tracks',)
        depth = 1

This will cause the tracks to nest without throwing the UI error.

Sign up to request clarification or add additional context in comments.

2 Comments

great, your solution works for me, although I don't understand why put the ForeignKey field 'tracks' like read_only_fields property/attribute and the depth. depth and read_only_fields are keywords attributes?
And the field serialized (tracks in this case) in the api rest framework is read only. How to make for the field can be updated via put or can be possible create a new instance? (album in this case ...)
0

One solution is to simply hide the HTML form on the browser side. For example, override Rest Framework's api.html template (by creating your_app/templates/rest_framework/api.html) and include the following:

{% extends "rest_framework/base.html" %}

...

{% block script %}
{{ block.super }}
    <script>
    $('.form-switcher a[name="html-tab"]').hide();
    $('.form-switcher a[name="raw-tab"]').tab('show')
</script>
{% endblock %}

If you want to keep the HTML form for your flat endpoints and simply remove it from your nested ones, you could use the name variable as an indicator. For instance, include "Nested" in the names of your nested endpoints and do something like this:

if("{{ name }}".indexOf("Nested") >= 0){
    $('.form-switcher a[name="html-tab"]').hide();
    $('.form-switcher a[name="raw-tab"]').tab('show').hide();
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.