I am using django-rest-framework to build out the back end. I have the list running fine, but (using the django-rest-framework admin screen) I cannot create an object by just using the Id fields of the foreign key objects. I hope I have this configured incorrectly, but I am open to writing some code if i have to :) I am learning django/python from a .NET and Java background and may have become a touch spoiled by this new stack.
Edit: I am trying not to use two different Model classes- I shouldn't have to right?
Thanks in advance.
From Chrome - the key bits of the request
Request URL:http://127.0.0.1:8000/rest/favorite_industries/
Request Method:POST
_content_type:application/json
_content:{
"user_id": 804 ,"industry_id": 20 }
The response
HTTP 400 BAD REQUEST
Vary: Accept
Content-Type: text/html; charset=utf-8
Allow: GET, POST, HEAD, OPTIONS
{
"user": [
"This field is required."
]
}
Ugh. Here are the key classes from django:
class FavoriteIndustry(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(User, related_name='favorite_industries')
industry = models.ForeignKey(Industry)
class Meta:
db_table = 'favorites_mas_industry'
class FavoriteIndustrySerializer(WithPkMixin, serializers.HyperlinkedModelSerializer):
class Meta:
model = myModels.FavoriteIndustry
fields = (
'id'
, 'user'
, 'industry'
)
Edit Adding the viewset:
class FavoriteIndustriesViewSet(viewsets.ModelViewSet):
#mixins.CreateModelMixin, viewsets.GenericViewSet):
paginate_by = 1
queryset = myModels\
.FavoriteIndustry\
.objects\
.select_related()
print 'SQL::FavoriteIndustriesViewSet: ' + str(queryset.query)
serializer_class = mySerializers.FavoriteIndustrySerializer
The get/list functionality generates decent JSON:
{"count": 2, "next": "http://blah.com/rest/favorite_industries/?page=2&format=json", "previous": null, "results": [{"id": 1, "user": "http://blah.com/rest/users/804/", "industry": {"industry_id": 2, "industry_name": "Consumer Discretionary", "parent_industry_name": "Consumer Discretionary", "category_name": "Industries"}}]}
Your code is using serializer only for validation, but it is possible use it to insert or update new objects on database calling serializer. save() . To save foreign keys using django-rest-framework you must put a related field on serializer to deal with it. Use PrimaryKeyRelatedField .
The HyperlinkedModelSerializer class is similar to the ModelSerializer class except that it uses hyperlinks to represent relationships, rather than primary keys. By default the serializer will include a url field instead of a primary key field.
The rendering process takes the intermediate representation of template and context, and turns it into the final byte stream that can be served to the client. REST framework includes a number of built in Renderer classes, that allow you to return responses with various media types.
Django-Knox is a framework that makes the authentication of the API endpoints built with the Django Rest Framework easier. However, Knox is also a token-based authentication like JSON Web Token (JWT) auth. Django-Knox comes with well-detailed documentation for easy implementation.
I have created a simplified mock up of your application.
models.py:
from django.db import models
from django.contrib.auth.models import User
class Industry(models.Model):
name = models.CharField(max_length=128)
class FavoriteIndustry(models.Model):
user = models.ForeignKey(User, related_name='favorite_industries')
industry = models.ForeignKey(Industry)
views.py:
from rest_framework import viewsets
from models import FavoriteIndustry
from serializers import FavoriteIndustrySerializer
class FavoriteIndustriesViewSet(viewsets.ModelViewSet):
queryset = FavoriteIndustry.objects.all()
serializer_class = FavoriteIndustrySerializer
serializers.py:
from rest_framework import serializers
from models import FavoriteIndustry, Industry
class FavoriteIndustrySerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = FavoriteIndustry
fields = ('id', 'user', 'industry')
urls.py:
from django.conf.urls import patterns, include, url
from core.api import FavoriteIndustriesViewSet
favorite_industries_list = FavoriteIndustriesViewSet.as_view({
'get': 'list',
'post': 'create'
})
urlpatterns = patterns('',
url(r'^favorite_industries/$', favorite_industries_list, name='favorite-industries-list'),
url(r'^users/(?P<pk>[0-9]+)/$', favorite_industries_list, name='user-detail'),
url(r'^industries/(?P<pk>[0-9]+)/$', favorite_industries_list, name='industry-detail'),
)
And here are a few tests:
>>>
>>> import json
>>> from django.test import Client
>>> from core.models import Industry
>>>
>>> industry = Industry(name='candy')
>>> industry.save()
>>>
>>> c = Client()
>>>
>>> response = c.get('http://localhost:8000/favorite_industries/')
>>> response.content
'[]'
>>>
>>> data = {
... 'user': 'http://localhost:8000/users/1/',
... 'industry': 'http://localhost:8000/industries/1/'
... }
>>>
>>> response = c.post('http://localhost:8000/favorite_industries/', json.dumps(data), 'application/json')
>>> response.content
'{"id": 1, "user": "http://testserver/users/1/", "industry": "http://testserver/industries/1/"}'
>>>
>>> response = c.get('http://localhost:8000/favorite_industries/')
>>> response.content
'[{"id": 1, "user": "http://testserver/users/1/", "industry": "http://testserver/industries/1/"}]'
>>>
Django REST Framework expects user
and industry
fields as URLs rather than ids since you are using HyperlinkedModelSerializer
.
In case you need to use object ids instead of URLs, use ModelSerializer
instead of HyperlinkedModelSerializer
and pass ids to user
and industry
:
serializers.py:
from rest_framework import serializers
from models import FavoriteIndustry, Industry
class FavoriteIndustrySerializer(serializers.ModelSerializer):
class Meta:
model = FavoriteIndustry
fields = ('id', 'user', 'industry')
And tests:
>>>
>>> import json
>>> from django.test import Client
>>> from core.models import Industry
>>>
>>> #industry = Industry(name='candy')
>>> #industry.save()
>>>
>>> c = Client()
>>>
>>> response = c.get('http://localhost:8000/favorite_industries/')
>>> response.content
'[{"id": 1, "user": 1, "industry": 1}, {"id": 2, "user": 1, "industry": 1}]'
>>>
>>> data = {
... 'user': 1,
... 'industry': 1
... }
>>>
>>> response = c.post('http://localhost:8000/favorite_industries/', json.dumps(data), 'application/json')
>>> response.content
'{"id": 3, "user": 1, "industry": 1}'
>>>
>>> response = c.get('http://localhost:8000/favorite_industries/')
>>> response.content
'[{"id": 1, "user": 1, "industry": 1}, {"id": 2, "user": 1, "industry": 1}, {"id": 3, "user": 1, "industry": 1}]'
>>>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With