{"id":1936,"date":"2016-06-22T15:48:28","date_gmt":"2016-06-22T14:48:28","guid":{"rendered":"http:\/\/www.jurecuhalev.com\/blog\/?p=1936"},"modified":"2016-06-22T15:49:12","modified_gmt":"2016-06-22T14:49:12","slug":"ember-server-side-form-validation-with-django","status":"publish","type":"post","link":"https:\/\/www.jurecuhalev.com\/blog\/ember-server-side-form-validation-with-django\/","title":{"rendered":"Ember Server Side Form validation with Django"},"content":{"rendered":"<p>In previous post (<a href=\"https:\/\/www.jurecuhalev.com\/blog\/2016\/06\/17\/ember-server-side-form-validation-with-mirage\/\">Ember Server Side Form validation with Mirage<\/a>), I&#8217;ve looked at just the Ember.js side. In this article, I&#8217;ll connect it with Django so that we have an actual backend that&#8217;s returning our errors. It builds on top of previous Ember.js code. There are also full Github repositories at the end.<\/p>\n<p>Lets start with Django. We&#8217;ll be using <a href=\"http:\/\/www.django-rest-framework.org\/\">Django Rest Framework<\/a> to generate server side Django.<\/p>\n<p>We have a basic <strong>models.py<\/strong>:<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\nfrom __future__ import unicode_literals\r\nfrom django.db import models\r\n\r\nclass Registration(models.Model):\r\n    GENDER_CHOICES = (\r\n        ('male', 'Male'),\r\n        ('female', 'Female'),\r\n        ('unspecified', 'Unspecified')\r\n    )\r\n\r\n    firstname = models.CharField(max_length=100)\r\n    lastname = models.CharField(max_length=100)\r\n    submitted = models.DateTimeField(auto_now_add=True)\r\n<\/pre>\n<p>and an API in views.py:<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\nfrom rest_framework import viewsets\r\nfrom rest_framework.response import Response\r\nfrom rest_framework import status\r\n\r\nfrom .models import Registration\r\nfrom .serializers import RegistrationSerializer\r\n\r\nclass RegistrationViewSet(viewsets.ViewSet):\r\n    def create(self, request):\r\n        serializer = RegistrationSerializer(data=request.data)\r\n        if serializer.is_valid():\r\n            serializer.save()\r\n            return Response(serializer.data, status=status.HTTP_201_CREATED)\r\n        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)\r\n<\/pre>\n<p>One thing to note &#8211; we return 400 Error code, instead of 422 that we mocked with Mirage. That is because Ember Django Adapter wraps 400 error to make it compatible with JSON API specification.<\/p>\n<p>All of our business logic of API validation happens in <strong>serializers.py<\/strong>:<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\nfrom rest_framework import serializers\r\n\r\nfrom . models import Registration\r\n\r\nclass RegistrationSerializer(serializers.ModelSerializer):\r\n    class Meta:\r\n        model = Registration\r\n        fields = ('id', 'firstname', 'lastname')\r\n   \r\n    def validate_firstname(self, value):\r\n    \tif 'john' not in value.lower():\r\n    \t\traise serializers.ValidationError('First name must be John')\r\n    \treturn value\r\n\r\n    def validate_lastname(self, value):\r\n\r\n    \tif 'smith' in value.lower():\r\n    \t\traise serializers.ValidationError(&quot;Last name can't be Smith&quot;)\r\n    \treturn value\r\n\r\n    def validate(self, data):\r\n    \tif data&#x5B;'firstname'] == 'John' and data&#x5B;'lastname'] == 'Doe':\r\n    \t\traise serializers.ValidationError(&quot;Please enter a more original name&quot;)\r\n<\/pre>\n<p>With server side in place, we can extend the previous example Ember.js app. We&#8217;ll be using <a href=\"http:\/\/dustinfarris.com\/ember-django-adapter\/\">Ember Django Adapter<\/a> to make things easier.<\/p>\n<p>First of, we need to turn of ember-cli-mirage in <strong>config\/environment.js<\/strong>. We also set the development URL and API namespace at the same time.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n  if (environment === 'development') {\r\n    ENV.APP.API_HOST = 'http:\/\/localhost:8000';\r\n    ENV.APP.API_NAMESPACE = 'api';\r\n\r\n    ENV&#x5B;'ember-cli-mirage'] = {\r\n      enabled: false\r\n    };\r\n  }\r\n<\/pre>\n<p>Another source of problems is that DS.RESTAdapter pluralises api endpoints. So instead of <i>\/api\/registration\/<\/i> it posts to <i>\/api\/registration<b>s<\/b>\/<\/i>. To make it stop doing that we can define &#8216;registration&#8217; as uncountable:<br \/>\n(<strong>ember generate drf-adapter application<\/strong>)<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nimport DRFAdapter from '.\/drf';\r\nimport Inflector from 'ember-inflector';\r\n\r\nconst inflector = Inflector.inflector;\r\ninflector.uncountable('registration');\r\n\r\nexport default DRFAdapter.extend({});\r\n<\/pre>\n<p>Controller is still the same:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nimport Ember from 'ember';\r\n\r\nexport default Ember.Controller.extend({\r\n  actions: {\r\n    save() {\r\n      var model = this.get('model');\r\n\r\n      model.save().then((registration) =&gt; {\r\n        \/\/ it's a mock, we don't do anything\r\n      }).catch((adapterError) =&gt; {\r\n        \/\/ we just need to catch error\r\n      });\r\n    }\r\n  }\r\n});\r\n<\/pre>\n<p>The main improvement is that template error handling now also displays non-field errors (via <strong>model.errors.base<\/strong>):<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n{{#each model.errors.base as |error|}}\r\n  &lt;span class=&quot;errors&quot;&gt;{{error.message}}&lt;\/span&gt;\r\n{{\/each}}\r\n\r\n&lt;form&gt;\r\n  &lt;p&gt;\r\n    &lt;label&gt;First name: {{input value=model.firstname}}&lt;\/label&gt;\r\n    {{#each model.errors.firstname as |error|}}\r\n      &lt;span class=&quot;errors&quot;&gt;{{error.message}}&lt;\/span&gt;\r\n    {{\/each}}\r\n  &lt;\/p&gt;\r\n  &lt;p&gt;\r\n    &lt;label&gt;Last name:\r\n      {{input value=model.lastname}}\r\n    &lt;\/label&gt;\r\n    {{#each model.errors.lastname as |error|}}\r\n      &lt;span class=&quot;errors&quot;&gt;{{error.message}}&lt;\/span&gt;\r\n    {{\/each}}\r\n  &lt;\/p&gt;\r\n  &lt;button {{action 'save'}}&gt;Save&lt;\/button&gt;\r\n&lt;\/form&gt;\r\n<\/pre>\n<p>With this in place, form validation errors now work correctly. If server side form validation passes, it also writes data into Data Store.<\/p>\n<p>Ember.js code is in &#8216;django-api&#8217; branch at <a href=\"https:\/\/github.com\/ember-examples\/server-side-validation-mirage\/tree\/django-api\">https:\/\/github.com\/ember-examples\/server-side-validation-mirage\/tree\/django-api<\/a><br \/>\nDjango code is at <a href=\"https:\/\/github.com\/ember-examples\/django-drf-serializer-validations\">https:\/\/github.com\/ember-examples\/django-drf-serializer-validations<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In previous post (Ember Server Side Form validation with Mirage), I&#8217;ve looked at just the Ember.js side. In this article, I&#8217;ll connect it with Django so that we have an actual backend that&#8217;s returning our errors. It builds on top of previous Ember.js code. There are also full Github repositories at the end. Lets start [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[12,925],"tags":[],"class_list":["post-1936","post","type-post","status-publish","format-standard","hentry","category-django","category-ember-js"],"acf":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.jurecuhalev.com\/blog\/wp-json\/wp\/v2\/posts\/1936","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.jurecuhalev.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.jurecuhalev.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.jurecuhalev.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.jurecuhalev.com\/blog\/wp-json\/wp\/v2\/comments?post=1936"}],"version-history":[{"count":6,"href":"https:\/\/www.jurecuhalev.com\/blog\/wp-json\/wp\/v2\/posts\/1936\/revisions"}],"predecessor-version":[{"id":1942,"href":"https:\/\/www.jurecuhalev.com\/blog\/wp-json\/wp\/v2\/posts\/1936\/revisions\/1942"}],"wp:attachment":[{"href":"https:\/\/www.jurecuhalev.com\/blog\/wp-json\/wp\/v2\/media?parent=1936"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.jurecuhalev.com\/blog\/wp-json\/wp\/v2\/categories?post=1936"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.jurecuhalev.com\/blog\/wp-json\/wp\/v2\/tags?post=1936"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}