Upgrade to Pro — share decks privately, control downloads, hide ads and more …

DJANGO AND MVC JAVASCRIPT FRAMEWORKS

Sean
August 16, 2013
360

DJANGO AND MVC JAVASCRIPT FRAMEWORKS

MVC JavaScript Frameworks are gaining momentum as a framework for building web apps. Backbone.js, AngularJS, and Ember.js all have significant followings as Open Source projects. Embedly recently rewrote their user app using Ember.js and learned a lot in the process.

This talk will focus on using Django to create a server backend for Ember.js. It will cover development, authentication, API endpoints and deployment.

Sean

August 16, 2013
Tweet

Transcript

  1. DJANGO
    AND
    MVC
    JAVASCRIPT
    FRAMEWORKS

    View Slide

  2. Sean Creeley
    @screeley
    [email protected]

    View Slide

  3. WHAT WE BUILT

    View Slide

  4. What is
    JavaScript MVC?

    View Slide

  5. View Slide

  6. Why Ember?

    View Slide

  7. Why
    JavaScript MVC?

    View Slide

  8. UP THE
    STACK

    View Slide

  9. View Slide

  10. View Slide

  11. BROWSERS
    GOT
    BETTER

    View Slide

  12. IE - 87.2%
    Firefox - 8.07%
    Safari: 3.2%
    Mozilla Suite - 0.52%
    Opera - 0.49%
    JULY 2005

    View Slide

  13. Chrome: 32.3 %
    IE: 22.2%
    Firefox: 18.5%
    Safari: 14.7%
    Opera: 2.3%
    JULY 2013

    View Slide

  14. XMLHttpRequest Web Standard
    jQuery Released
    Internet Explorer 7
    2006
    2007
    iPhone Released
    2008
    Google Chrome

    View Slide

  15. APIS ARE
    KING

    View Slide

  16. USE
    THE
    GOOD PARTS

    View Slide

  17. EMBER INTRO

    View Slide

  18. APPLICATION
    window.Dolphin = Em.Application.create({
    rootElement: $('#dolphin'),
    ready: function(){}
    });

    View Slide

  19. ROUTER
    Dolphin.Router.map(function() {
    this.route('about');
    this.resource('company', function(){
    this.route('team');
    });
    });
    /
    /about
    /company
    /company/team

    View Slide

  20. TEMPLATES


    {{outlet}}


    Welcome to Dolphin!
    Helping Dolphins become the smartest species
    since 2013
    application.handlebars
    index.handlebars

    View Slide

  21. MODELS
    Dolphin.CompanyTeamRoute = Em.Route.extend({
    model: function(){
    return {name: 'sean'}
    }
    });

    {{name}}

    company/team.handlebars

    View Slide

  22. MODELS
    Dolphin.CompanyTeamRoute = Em.Route.extend({
    model: function(){
    return [
    {name: 'sean'},
    {name: 'kawandeep'},
    {name: 'andy'}]
    }
    });

    {{#each controller}}
    {{name}}
    {{/each}}

    View Slide

  23. MODELS
    Dolphin.CompanyTeamRoute = Em.Route.extend({
    model: function(){
    return Dolphin.User.find({is_team: true});
    }
    });
    Dolphin.CompanyTeamRoute = Em.Route.extend({
    model: function(){
    return $.getJSON(‘/api/users’, {is_team :true});
    }
    });

    View Slide

  24. MODELS
    Dolphin.User = DS.Model.extend({
    profile: DS.belongsTo('Dolphin.Profile'),
    first_name: DS.attr('string'),
    last_name: DS.attr('string'),
    username: DS.attr('string'),
    email: DS.attr('string')
    });

    View Slide

  25. CONTROLLERS
    Dolphin.CompanyTeamController =
    Em.ArrayController.extend({
    sortAscending: ['years_coding'],
    totalYears: function(){
    return this.reduce(function(total, user) {
    return total + user.get('years_coding');
    }, 0);
    }.property('@each.years_coding')
    });

    View Slide

  26. VIEWS
    Dolphin.CompanyTeamView = Em.View.extend({
    didInsertElement: function () {
    // fade images in.
    this.$().find('img').animate({
    opacity: 1
    }, 2000);
    }
    });

    View Slide

  27. DJANGO
    DEVELOPMENT

    View Slide

  28. #1
    SEPARATE
    FRONTEND
    AND
    BACKEND
    DEVELOPMENT

    View Slide

  29. USE GRUNT
    #2

    View Slide

  30. #3
    ALLOW XSS
    HEADERS

    View Slide

  31. XSS_ORIGINS = 'http://localhost.com:3501'
    XSS_METHODS = ['POST', 'GET', 'OPTIONS', 'PUT', 'DELETE']
    XSS_HEADERS = ['Content-Type', 'x-requested-with', '*']
    XSS_CREDENTIALS = 'true'
    class XSSharing(object):
    def process_response(self, request, response):
    response['Access-Control-Allow-Origin'] = XSS_ORIGINS
    response['Access-Control-Allow-Methods'] \
    = ",".join(XSS_METHODS)
    response['Access-Control-Allow-Headers'] \
    = ",".join(XSS_HEADERS)
    response['Access-Control-Allow-Credentials'] \
    = XSS_CREDENTIALS
    return response
    https://gist.github.com/426829

    View Slide

  32. #4
    WRITE AN
    API
    YOURSELF

    View Slide

  33. urlpatterns = patterns('',
    url(r'^admin/', include(admin.site.urls)),
    url(r'^api/users(\/(?P\d+))?',
    UserView.as_view()),
    )
    urls.py

    View Slide

  34. from django.views.generic.base import View
    from django.http import HttpResponse
    from django.contrib.auth.models import User
    from django.forms.models import model_to_dict
    class UserView(View):
    def serialize(self, obj):
    return model_to_dict(obj,
    fields=['id', 'first_name', 'last_name', 'email'])
    def get(self, request, pk=None):
    if pk is not None:
    data = {'user': self.serialize(User.objects.get(pk=pk))}
    elif request.GET:
    data = {'users' : map(self.serialize,
    User.objects.filter(**request.GET))}
    else:
    data = {'users' : map(self.serialize, User.objects.all())}
    return HttpResponse(json.dumps(data), mimetype="application/json")
    views.py

    View Slide

  35. users.js
    Dolphin.User = DS.Model.extend({
    first_name: DS.attr('string'),
    last_name: DS.attr('string'),
    email: DS.attr('string')
    });
    >> var user = Dolphin.User.find(1);
    >> user.get(‘first_name’)
    “sean”

    View Slide

  36. #5
    MAKE THE
    FRONTEND
    DUMB

    View Slide

  37. #6
    AUTHENTICATE

    View Slide

  38. class UserAuth(auth.Auth):
    def can_access(self, request, obj):
    if request.user.id == obj.id:
    return True
    if request.user.is_superuser:
    return True
    return False
    class UserView(ember.View):
    ...
    def get(self, request, pk, **kwargs):
    obj = self.model.objects.get(pk=pk)
    if not self.auth.can_access(request, obj):
    raise ValueError('no auth specified')
    return self.serializer.one(obj)
    ember.register(User, UserSerializer, UserView, auth=UserAuth())

    View Slide

  39. #7
    MIX
    AND
    MATCH

    View Slide

  40. #8
    USE
    RELATIONS

    View Slide

  41. class Author(models.Model):
    first_name = models.CharField()
    last_name = models.CharField()
    class Book(models.Model):
    author = models.ForeignKey(Author)
    title = models.CharField()
    models.py

    View Slide

  42. Dolphin.Author = DS.Model.extend({
    books: DS.hasMany('Dolphin.Book'),
    first_name: DS.attr('string'),
    last_name: DS.attr('string')
    });
    Dolphin.Book = DS.Model.extend({
    author: DS.belongsTo('Dolphin.Author'),
    title: DS.attr('string'),
    });
    models.js

    View Slide

  43. #9
    DON’T PASS
    BACK ALL
    FIELDS

    View Slide

  44. #10
    JQUERY IS NOT
    THE ENEMY.

    View Slide

  45. App.CommentView = Em.View.extend({
    template: Em.Handlebars.compile(
    '{{name}}{{{body}}}'),
    didInsertElement: function(){
    this.$().find('p').animate({
    opacity: 1
    }, 1000);
    }
    });

    View Slide

  46. #11
    WORRY

    View Slide

  47. {
    "blogs": [
    {
    "id": 1,
    "name": "Embedly Blog"
    },
    {
    "id": 1,
    "name": "Embedly Blog"
    },
    ....
    ]
    }
    /api/blogs

    View Slide

  48. {"users": [
    {
    "id": 1,
    "name": "Sean",
    "email": "[email protected]"
    },
    {
    "id": 2,
    "name": "Kawandeep",
    "email": "[email protected]"
    },
    ....
    ]}
    /api/users

    View Slide

  49. #12
    DEPLOY STATIC

    View Slide

  50. #13
    deferReadiness
    IS YOUR
    FRIEND

    View Slide

  51. App.deferReadiness();
    // Wait for all the javascript files to load.
    $(document).ready(function(){
    App.User.current(function(user, profile,
    organizations){
    // Set everything else up.
    App.set('user', user);
    // Will start everything up.
    App.advanceReadiness();
    });
    });

    View Slide

  52. #11
    IT’S PROBABLY
    NOT EMBER’S
    FAULT.

    View Slide

  53. QUESTIONS?
    @screeley
    @embedly

    View Slide