Sebastian
Sebastian

Reputation: 61

Django REST framework: nested relationship: non_field_errors

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!

Upvotes: 6

Views: 2578

Answers (2)

John R.B. Palmer
John R.B. Palmer

Reputation: 2092

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();
}

Upvotes: 0

Keith Morris
Keith Morris

Reputation: 275

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.

Upvotes: 3

Related Questions