Using Django as Ember.js back-end
Ember.js is moving a lot, but since the adoption of JSONAPI for the default "wire protocol" with back-ends it's easier to keep up.
I have had good luck using the Django Rest Framework JSON API library on top of Django Rest Framework.
This post will try to document how to get things working and forget about your back-end for a while. I'm going to follow the Django Tutorial schema, with an important addition of adding a related_name
to the ForeignKey
field.
from django.db import models
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name="choices")
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
Do the usual makemigrations
and migrate
then also register the models in the Admin.
Install Django Rest Framework and the aforementioned JSON API adapter. Also install django-filter
. In the settings.py, make sure you add rest_framework
.
pip install django-rest-framework
pip install git+https://github.com/django-json-api/django-rest-framework-json-api.git@develop --upgrade # FIXME once 2.0 is properly released it should be enough
pip install django-filter
Now configure the DRF like so:
REST_FRAMEWORK = {
#'PAGE_SIZE': 10,
# Use Django's standard `django.contrib.auth` permissions,
# or allow read-only access for unauthenticated users.
# FIXME do permission and authentication as you see fit.
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny'
],
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
#'rest_framework.authentication.SessionAuthentication',
],
'EXCEPTION_HANDLER': 'rest_framework_json_api.exceptions.exception_handler',
'DEFAULT_PAGINATION_CLASS':
'rest_framework_json_api.pagination.PageNumberPagination',
'DEFAULT_PARSER_CLASSES': (
'rest_framework_json_api.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser'
),
'DEFAULT_RENDERER_CLASSES': (
'rest_framework_json_api.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
),
'DEFAULT_METADATA_CLASS': 'rest_framework_json_api.metadata.JSONAPIMetadata',
# this is optional but very useful
'DEFAULT_FILTER_BACKENDS': ('rest_framework.filters.DjangoFilterBackend',),
}
APPEND_SLASH=False
JSON_API_FORMAT_KEYS = 'dasherize'
JSON_API_FORMAT_RELATION_KEYS = 'dasherize'
JSON_API_PLURALIZE_RELATION_TYPE = True
Now create a new rest.py
file:
from .models import Question, Choice
from rest_framework_json_api import serializers, relations
from rest_framework import viewsets, views, response
import django_filters
from rest_framework import filters
class QuestionSerializer(serializers.ModelSerializer):
choices = relations.ResourceRelatedField(read_only=True, many=True)
class Meta:
model = Question
class ChoiceSerializer(serializers.ModelSerializer):
class Meta:
model = Choice
class QuestionViewSet(viewsets.ModelViewSet):
queryset = Question.objects.all()
serializer_class = QuestionSerializer
class ChoiceViewSet(viewsets.ModelViewSet):
queryset = Choice.objects.all()
serializer_class = ChoiceSerializer
# this is should plural and dasherized names
ROUTES = {
'questions': QuestionViewSet,
'choices': ChoiceViewSet
}
Then in the global urls.py
:
from rest_framework import routers
router = routers.DefaultRouter(trailing_slash=False)
from polls.rest import ROUTES
for key, viewset in ROUTES.items():
router.register(key, viewset)
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/v1/', include(router.urls)),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
The only Ember change you have to do is generate an application adapter with this content:
import DS from 'ember-data';
export default DS.JSONAPIAdapter.extend({
namespace: 'api/v1',
isInvalid(status, headers, payload) {
return status === 422 || status === 400;
},
});
Now run the Django dev server, and don't forget to use ember serve --proxy http://127.0.0.1:8000
to ensure your Ember app can easily make Ajax requests there.