Reputation: 61
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
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
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