{"id":254,"date":"2016-02-16T12:08:43","date_gmt":"2016-02-16T18:08:43","guid":{"rendered":"http:\/\/timothypoon.com\/blog\/?p=254"},"modified":"2016-02-19T09:03:13","modified_gmt":"2016-02-19T15:03:13","slug":"ember-and-django-get-friendly","status":"publish","type":"post","link":"https:\/\/timothypoon.com\/blog\/2016\/02\/16\/ember-and-django-get-friendly\/","title":{"rendered":"Ember and Django Get Friendly"},"content":{"rendered":"<p>Like a turducken or cherpumple, we&#8217;re going to stick Ember right into the guts of Django.<\/p>\n<p>Let&#8217;s get this out of the way: this is not ideal. Doing something like having Django power just the API through the <a href=\"http:\/\/www.django-rest-framework.org\/\">Django REST Framework<\/a> and then having Ember do all user-facing things would be smarter. Having the separation is easier for maintenance and clearly defines responsibilities.<\/p>\n<p>Unfortunately, real life is rarely ideal. Your website may have some static pages that necessarily need to be served away from the monolithic stature of Ember, but in keeping assets reusable, they&#8217;re still tied into the front end builds. Or you may have deployment requirements that necessitate keeping this tightly bundled. Either way, we&#8217;re here now, so let&#8217;s figure it out.<\/p>\n<h3>The Django Part<\/h3>\n<p>Getting Django set up is fairly straightforward, as prescribed by the <a href=\"https:\/\/docs.djangoproject.com\/en\/1.9\/intro\/install\/\">Django docs<\/a>. The basics on OS X go something like this.<\/p>\n<div class=\"codecolorer-container bash railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;\"><div class=\"bash codecolorer\">$ brew <span class=\"kw2\">install<\/span> python3<br \/>\n$ brew <span class=\"kw2\">install<\/span> pyenv <span class=\"co0\"># Additional steps at https:\/\/github.com\/yyuu\/pyenv#homebrew-on-mac-os-x<\/span><br \/>\n$ pyenv virtualenv <span class=\"re5\">--python<\/span>=$<span class=\"br0\">&#40;<\/span><span class=\"kw2\">which<\/span> python3<span class=\"br0\">&#41;<\/span> myenv<br \/>\n$ pyenv activate myenv<br \/>\n$ pip <span class=\"kw2\">install<\/span> <span class=\"re2\">Django<\/span>==1.9.2<br \/>\n$ django-admin startproject myapp<br \/>\n$ <span class=\"kw3\">cd<\/span> myapp<span class=\"sy0\">\/<\/span><br \/>\n$ python manage.py startapp app1<\/div><\/div>\n<p>This will install Python 3.x and pyenv, create a virtualenv called <code class=\"codecolorer text geshi\"><span class=\"text\">myenv<\/span><\/code>, install Django v1.9.2 to it, and then create a skeleton project in the <code class=\"codecolorer text geshi\"><span class=\"text\">myapp<\/span><\/code> directory with a single <code class=\"codecolorer text geshi\"><span class=\"text\">app1<\/span><\/code> application.<\/p>\n<p>I like to structure my Django projects a particular way since they tend to have multiple apps but a singular source of deployment settings.<\/p>\n<div class=\"codecolorer-container bash railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;\"><div class=\"bash codecolorer\">myapp<br \/>\n\u2502 &nbsp; manage.py<br \/>\n\u2502 &nbsp; ...<br \/>\n\u2502<br \/>\n\u251c\u2500\u2500\u2500apps<br \/>\n\u2502 &nbsp; \u251c\u2500\u2500\u2500app1<br \/>\n\u2502 &nbsp; \u2502 &nbsp; \u2502 &nbsp; models.py<br \/>\n\u2502 &nbsp; \u2502 &nbsp; \u2502 &nbsp; views.py<br \/>\n\u2502 &nbsp; \u2502 &nbsp; \u2502 &nbsp; ...<br \/>\n\u2502 &nbsp; \u2502<br \/>\n\u2502 &nbsp; \u251c\u2500\u2500\u2500app2<br \/>\n\u2502 &nbsp; \u2502 &nbsp; \u2502 &nbsp; models.py<br \/>\n\u2502 &nbsp; \u2502 &nbsp; \u2502 &nbsp; views.py<br \/>\n\u2502 &nbsp; \u2502 &nbsp; \u2502 &nbsp; ...<br \/>\n\u2502 &nbsp; \u2502<br \/>\n\u251c\u2500\u2500\u2500deployment<br \/>\n\u2502 &nbsp; \u2502 &nbsp; settings.py<br \/>\n\u2502 &nbsp; \u2502 &nbsp; urls.py<br \/>\n\u2502 &nbsp; \u2502 &nbsp; ...<\/div><\/div>\n<p>This does require some changes to fit into this new structure, however.<\/p>\n<div class=\"codecolorer-container python railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/>9<br \/>10<br \/>11<br \/>12<br \/>13<br \/>14<br \/>15<br \/>16<br \/><\/div><\/td><td><div class=\"python codecolorer\"><span class=\"co1\"># manage.py L6<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw3\">os<\/span>.<span class=\"me1\">environ<\/span>.<span class=\"me1\">setdefault<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'DJANGO_SETTINGS_MODULE'<\/span><span class=\"sy0\">,<\/span> <span class=\"st0\">'deployment.settings'<\/span><span class=\"br0\">&#41;<\/span><br \/>\n<br \/>\n<span class=\"co1\"># \/deployment\/settings.py<\/span><br \/>\nINSTALLED_APPS <span class=\"sy0\">=<\/span> <span class=\"br0\">&#91;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"st0\">'django.contrib.admin'<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; <span class=\"st0\">'django.contrib.auth'<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; <span class=\"st0\">'django.contrib.contenttypes'<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; <span class=\"st0\">'django.contrib.sessions'<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; <span class=\"st0\">'django.contrib.messages'<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; <span class=\"st0\">'django.contrib.staticfiles'<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; <span class=\"st0\">'apps.app1'<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; <span class=\"st0\">'apps.app2'<\/span><span class=\"sy0\">,<\/span><br \/>\n<span class=\"br0\">&#93;<\/span><br \/>\n<br \/>\nROOT_URLCONF <span class=\"sy0\">=<\/span> <span class=\"st0\">'deployment.urls'<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n<p>And remember that you&#8217;ll now be doing imports like <code class=\"codecolorer text geshi\"><span class=\"text\">from apps.yourapp import models<\/span><\/code> instead of <code class=\"codecolorer text geshi\"><span class=\"text\">from yourapp import models<\/span><\/code>.<\/p>\n<h3>The Ember Part<\/h3>\n<p>The cool part about Ember these days is <a href=\"http:\/\/ember-cli.com\/\">Ember CLI<\/a>, which facilitates a great deal of abiding the framework&#8217;s directory requirements. We&#8217;ll continue with getting that all set up.<\/p>\n<div class=\"codecolorer-container bash railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;\"><div class=\"bash codecolorer\">$ brew <span class=\"kw2\">install<\/span> node<br \/>\n$ npm <span class=\"kw2\">install<\/span> <span class=\"re5\">-g<\/span> ember-cli<br \/>\n$ npm <span class=\"kw2\">install<\/span> <span class=\"re5\">-g<\/span> bower<br \/>\n$ brew <span class=\"kw2\">install<\/span> watchman<br \/>\n$ npm <span class=\"kw2\">install<\/span> <span class=\"re5\">-g<\/span> phantomjs<br \/>\n$ ember new frontendapp<\/div><\/div>\n<p>If you&#8217;re using Git for source control (and you should be, you dummy), this will create a separate Git repo inside <code class=\"codecolorer text geshi\"><span class=\"text\">\/frontendapp\/.git<\/span><\/code>, so you might want to remove that.<\/p>\n<p>And if you&#8217;re using Submline Text as a text editor, the Ember CLI user guide has a <a href=\"http:\/\/ember-cli.com\/user-guide\/#sublime-text\">good tip<\/a> about performance.<\/p>\n<h3>Hooking It All Up<\/h3>\n<p>The key now is to get Ember to build into a directory that Django will point to as static files. Then they can be served from whatever view you want as a template file.<\/p>\n<div class=\"codecolorer-container bash railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;\"><div class=\"bash codecolorer\">$ <span class=\"kw3\">cd<\/span> frontendapp<span class=\"sy0\">\/<\/span><br \/>\n$ ember serve <span class=\"re5\">--output-path<\/span> ..<span class=\"sy0\">\/<\/span>static<span class=\"sy0\">\/<\/span> <span class=\"re5\">--live-reload<\/span>=<span class=\"kw2\">false<\/span><\/div><\/div>\n<p>By running this during development, you&#8217;ll get the constant Ember builds being thrown into <code class=\"codecolorer text geshi\"><span class=\"text\">static\/<\/span><\/code> without the live reload feature since that&#8217;s unnecessary with what we&#8217;re doing.<\/p>\n<p>Next you&#8217;ll want to edit the <code class=\"codecolorer text geshi\"><span class=\"text\">deployment\/settings.py<\/span><\/code> file to get Django to serve the static files properly.<\/p>\n<div class=\"codecolorer-container python railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/>9<br \/>10<br \/>11<br \/>12<br \/>13<br \/>14<br \/>15<br \/>16<br \/>17<br \/>18<br \/>19<br \/>20<br \/>21<br \/>22<br \/>23<br \/>24<br \/><\/div><\/td><td><div class=\"python codecolorer\">TEMPLATES <span class=\"sy0\">=<\/span> <span class=\"br0\">&#91;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"st0\">'BACKEND'<\/span>: <span class=\"st0\">'django.template.backends.django.DjangoTemplates'<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"st0\">'DIRS'<\/span>: <span class=\"br0\">&#91;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw3\">os<\/span>.<span class=\"me1\">path<\/span>.<span class=\"me1\">join<\/span><span class=\"br0\">&#40;<\/span>BASE_DIR<span class=\"sy0\">,<\/span> <span class=\"st0\">'templates'<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw3\">os<\/span>.<span class=\"me1\">path<\/span>.<span class=\"me1\">join<\/span><span class=\"br0\">&#40;<\/span>BASE_DIR<span class=\"sy0\">,<\/span> <span class=\"st0\">'static'<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"st0\">'APP_DIRS'<\/span>: <span class=\"kw2\">True<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"st0\">'OPTIONS'<\/span>: <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"st0\">'context_processors'<\/span>: <span class=\"br0\">&#91;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"st0\">'django.template.context_processors.debug'<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"st0\">'django.template.context_processors.request'<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"st0\">'django.contrib.auth.context_processors.auth'<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"st0\">'django.contrib.messages.context_processors.messages'<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n<span class=\"br0\">&#93;<\/span><br \/>\n<br \/>\nSTATIC_URL <span class=\"sy0\">=<\/span> <span class=\"st0\">'\/static\/'<\/span><br \/>\n<br \/>\nSTATICFILES_DIRS <span class=\"sy0\">=<\/span> <span class=\"br0\">&#40;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw3\">os<\/span>.<span class=\"me1\">path<\/span>.<span class=\"me1\">join<\/span><span class=\"br0\">&#40;<\/span>BASE_DIR<span class=\"sy0\">,<\/span> <span class=\"st0\">'static'<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span><br \/>\n<span class=\"br0\">&#41;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n<p>And now we&#8217;ll get Ember to look in the right places. We&#8217;ll be using <a href=\"https:\/\/www.npmjs.com\/package\/ember-cli-replace\">ember-cli-replace<\/a> to manage environment replacements.<\/p>\n<div class=\"codecolorer-container javascript railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/>9<br \/>10<br \/>11<br \/>12<br \/>13<br \/>14<br \/>15<br \/>16<br \/>17<br \/>18<br \/>19<br \/>20<br \/>21<br \/>22<br \/>23<br \/>24<br \/>25<br \/>26<br \/>27<br \/>28<br \/>29<br \/><\/div><\/td><td><div class=\"javascript codecolorer\"><span class=\"co1\">\/\/ frontendapp\/package.json<\/span><br \/>\n<span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; ...<br \/>\n&nbsp; &nbsp; <span class=\"st0\">&quot;devDependencies&quot;<\/span><span class=\"sy0\">:<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; ...<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"st0\">&quot;ember-cli-replace&quot;<\/span><span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;0.2.1&quot;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><br \/>\n<br \/>\n<span class=\"co1\">\/\/ frontendapp\/config\/environment.js<\/span><br \/>\n<span class=\"kw1\">var<\/span> ENV <span class=\"sy0\">=<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; ...<br \/>\n&nbsp; &nbsp; <span class=\"me1\">baseURL<\/span><span class=\"sy0\">:<\/span> <span class=\"st0\">'\/frontendapp\/'<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; apiURL<span class=\"sy0\">:<\/span> <span class=\"st0\">'\/api'<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n<span class=\"co1\">\/\/ frontendapp\/ember-cli-build.js<\/span><br \/>\nmodule.<span class=\"me1\">exports<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span>defaults<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; ...<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/span> replacements <span class=\"sy0\">=<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; assetsURL<span class=\"sy0\">:<\/span> <span class=\"st0\">'\/static\/assets'<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; imagesURL<span class=\"sy0\">:<\/span> <span class=\"st0\">'\/static\/images'<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">for<\/span> <span class=\"br0\">&#40;<\/span><span class=\"kw1\">var<\/span> key <span class=\"kw1\">in<\/span> replacements<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; app.<span class=\"me1\">options<\/span>.<span class=\"me1\">replace<\/span>.<span class=\"me1\">patterns<\/span>.<span class=\"me1\">push<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; match<span class=\"sy0\">:<\/span> key<span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; replacement<span class=\"sy0\">:<\/span> replacements<span class=\"br0\">&#91;<\/span>key<span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n<p>So now you can use <code class=\"codecolorer text geshi\"><span class=\"text\">@@assetURL<\/span><\/code> and <code class=\"codecolorer text geshi\"><span class=\"text\">@@imagesURL<\/span><\/code> in place of hardcoding URLs in <code class=\"codecolorer text geshi\"><span class=\"text\">frontendapp\/app\/index.html<\/span><\/code>. (And don&#8217;t forget to rerun <code class=\"codecolorer text geshi\"><span class=\"text\">npm install<\/span><\/code>.)<\/p>\n<div class=\"codecolorer-container html4strict railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/><\/div><\/td><td><div class=\"html4strict codecolorer\"><span class=\"sc2\">&lt;<a href=\"http:\/\/december.com\/html\/4\/element\/link.html\"><span class=\"kw2\">link<\/span><\/a> <span class=\"kw3\">rel<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;stylesheet&quot;<\/span> <span class=\"kw3\">href<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;@@assetsURL\/vendor.css&quot;<\/span> <span class=\"sy0\">\/<\/span>&gt;<\/span><br \/>\n<span class=\"sc2\">&lt;<a href=\"http:\/\/december.com\/html\/4\/element\/link.html\"><span class=\"kw2\">link<\/span><\/a> <span class=\"kw3\">rel<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;stylesheet&quot;<\/span> <span class=\"kw3\">href<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;@@assetsURL\/tourf.css&quot;<\/span> <span class=\"sy0\">\/<\/span>&gt;<\/span><br \/>\n<br \/>\n<span class=\"sc2\">&lt;<a href=\"http:\/\/december.com\/html\/4\/element\/script.html\"><span class=\"kw2\">script<\/span><\/a> <span class=\"kw3\">src<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;@@assetsURL\/vendor.js&quot;<\/span>&gt;&lt;<span class=\"sy0\">\/<\/span><a href=\"http:\/\/december.com\/html\/4\/element\/script.html\"><span class=\"kw2\">script<\/span><\/a>&gt;<\/span><br \/>\n<span class=\"sc2\">&lt;<a href=\"http:\/\/december.com\/html\/4\/element\/script.html\"><span class=\"kw2\">script<\/span><\/a> <span class=\"kw3\">src<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;@@assetsURL\/tourf.js&quot;<\/span>&gt;&lt;<span class=\"sy0\">\/<\/span><a href=\"http:\/\/december.com\/html\/4\/element\/script.html\"><span class=\"kw2\">script<\/span><\/a>&gt;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n<p>If you have <code class=\"codecolorer text geshi\"><span class=\"text\">app1<\/span><\/code> deal with all the Django-based pages and <code class=\"codecolorer text geshi\"><span class=\"text\">app2<\/span><\/code> act as the API, you can set up the various <code class=\"codecolorer text geshi\"><span class=\"text\">urls.py<\/span><\/code> files to take care of everything.<\/p>\n<div class=\"codecolorer-container python railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/>9<br \/>10<br \/>11<br \/>12<br \/>13<br \/>14<br \/>15<br \/>16<br \/>17<br \/>18<br \/>19<br \/>20<br \/>21<br \/>22<br \/>23<br \/>24<br \/>25<br \/>26<br \/><\/div><\/td><td><div class=\"python codecolorer\"><span class=\"co1\"># deployment\/urls.py<\/span><br \/>\nurlpatterns <span class=\"sy0\">=<\/span> <span class=\"br0\">&#91;<\/span><br \/>\n&nbsp; &nbsp; url<span class=\"br0\">&#40;<\/span>r<span class=\"st0\">'^admin\/'<\/span><span class=\"sy0\">,<\/span> admin.<span class=\"kw3\">site<\/span>.<span class=\"me1\">urls<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; url<span class=\"br0\">&#40;<\/span>r<span class=\"st0\">'^'<\/span><span class=\"sy0\">,<\/span> include<span class=\"br0\">&#40;<\/span><span class=\"st0\">'apps.app1.urls'<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; url<span class=\"br0\">&#40;<\/span>r<span class=\"st0\">'^api\/'<\/span><span class=\"sy0\">,<\/span> include<span class=\"br0\">&#40;<\/span><span class=\"st0\">'apps.app2.urls'<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span><br \/>\n<span class=\"br0\">&#93;<\/span><br \/>\n<br \/>\n<span class=\"co1\"># apps\/app1\/urls.py<\/span><br \/>\nurlpatterns <span class=\"sy0\">=<\/span> <span class=\"br0\">&#91;<\/span><br \/>\n&nbsp; &nbsp; url<span class=\"br0\">&#40;<\/span>r<span class=\"st0\">'^$'<\/span><span class=\"sy0\">,<\/span> views.<span class=\"me1\">index<\/span><span class=\"sy0\">,<\/span> name<span class=\"sy0\">=<\/span><span class=\"st0\">'index'<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; url<span class=\"br0\">&#40;<\/span>r<span class=\"st0\">'^frontendapp\/'<\/span><span class=\"sy0\">,<\/span> views.<span class=\"me1\">frontendapp<\/span><span class=\"sy0\">,<\/span> name<span class=\"sy0\">=<\/span><span class=\"st0\">'frontendapp'<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span><br \/>\n<span class=\"br0\">&#93;<\/span><br \/>\n<br \/>\n<span class=\"co1\"># apps\/app1\/views.py<\/span><br \/>\n<span class=\"kw1\">def<\/span> index<span class=\"br0\">&#40;<\/span>request<span class=\"br0\">&#41;<\/span>:<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">return<\/span> render<span class=\"br0\">&#40;<\/span>request<span class=\"sy0\">,<\/span> <span class=\"st0\">'main.html'<\/span><span class=\"br0\">&#41;<\/span><br \/>\n<br \/>\n<span class=\"kw1\">def<\/span> frontendapp<span class=\"br0\">&#40;<\/span>request<span class=\"br0\">&#41;<\/span>:<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">return<\/span> render<span class=\"br0\">&#40;<\/span>request<span class=\"sy0\">,<\/span> <span class=\"st0\">'index.html'<\/span><span class=\"br0\">&#41;<\/span><br \/>\n<br \/>\n<span class=\"co1\"># apps\/app2\/urls.py<\/span><br \/>\nurlpatterns <span class=\"sy0\">=<\/span> <span class=\"br0\">&#91;<\/span><br \/>\n&nbsp; &nbsp; url<span class=\"br0\">&#40;<\/span>r<span class=\"st0\">'^persons\/(?P&lt;game_id&gt;[^\/]+)?'<\/span><span class=\"sy0\">,<\/span> views.<span class=\"me1\">persons<\/span><span class=\"sy0\">,<\/span> name<span class=\"sy0\">=<\/span><span class=\"st0\">'persons'<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; url<span class=\"br0\">&#40;<\/span>r<span class=\"st0\">'^places\/(?P&lt;team_id&gt;[^\/]+)?'<\/span><span class=\"sy0\">,<\/span> views.<span class=\"me1\">places<\/span><span class=\"sy0\">,<\/span> name<span class=\"sy0\">=<\/span><span class=\"st0\">'places'<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; url<span class=\"br0\">&#40;<\/span>r<span class=\"st0\">'^things\/(?P&lt;bracket_id&gt;[^\/]+)?'<\/span><span class=\"sy0\">,<\/span> views.<span class=\"me1\">things<\/span><span class=\"sy0\">,<\/span> name<span class=\"sy0\">=<\/span><span class=\"st0\">'things'<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span><br \/>\n<span class=\"br0\">&#93;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n<p>The resulting directory and file structure should look something like this once you have Ember building and whatnot.<\/p>\n<div class=\"codecolorer-container bash railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;\"><div class=\"bash codecolorer\">myapp<br \/>\n\u2502 &nbsp; manage.py<br \/>\n\u2502 &nbsp; ...<br \/>\n\u2502<br \/>\n\u251c\u2500\u2500\u2500frontendapp<br \/>\n\u2502 &nbsp; \u2502 &nbsp; package.json<br \/>\n\u2502 &nbsp; \u2502 &nbsp; ember-cli-build.js<br \/>\n\u2502 &nbsp; \u2502 &nbsp; ...<br \/>\n\u2502 &nbsp; \u2502<br \/>\n\u2502 &nbsp; \u251c\u2500\u2500\u2500config<br \/>\n\u2502 &nbsp; \u2502 &nbsp; \u2502 &nbsp; environment.js<br \/>\n\u2502 &nbsp; \u2502<br \/>\n\u2502 &nbsp; \u251c\u2500\u2500\u2500app<br \/>\n\u2502 &nbsp; \u2502 &nbsp; \u2502 &nbsp; index.html<br \/>\n\u2502 &nbsp; \u2502 &nbsp; \u2502 &nbsp; app.js<br \/>\n\u2502 &nbsp; \u2502 &nbsp; \u2502 &nbsp; router.js<br \/>\n\u2502 &nbsp; \u2502 &nbsp; \u2502 &nbsp; ...<br \/>\n\u2502 &nbsp; \u2502 &nbsp; \u2502<br \/>\n\u2502 &nbsp; \u2502 &nbsp; \u251c\u2500\u2500\u2500styles<br \/>\n\u2502 &nbsp; \u2502 &nbsp; \u251c\u2500\u2500\u2500templates<br \/>\n\u2502 &nbsp; \u2502 &nbsp; \u2514\u2500\u2500\u2500...<br \/>\n\u2502 &nbsp; \u2502<br \/>\n\u2502 &nbsp; \u251c\u2500\u2500\u2500public<br \/>\n\u2502 &nbsp; \u2514\u2500\u2500\u2500...<br \/>\n\u2502<br \/>\n\u251c\u2500\u2500\u2500static<br \/>\n\u2502 &nbsp; \u2502 &nbsp; index.html<br \/>\n\u2502 &nbsp; \u2502 &nbsp; ...<br \/>\n\u2502 &nbsp; \u2502<br \/>\n\u2502 &nbsp; \u251c\u2500\u2500\u2500assets<br \/>\n\u2502 &nbsp; \u251c\u2500\u2500\u2500images<br \/>\n\u2502 &nbsp; \u2514\u2500\u2500\u2500...<br \/>\n\u2502<br \/>\n\u251c\u2500\u2500\u2500templates<br \/>\n\u2502 &nbsp; \u2502 &nbsp; main.html<br \/>\n\u2502 &nbsp; \u2502 &nbsp; ...<br \/>\n\u2502<br \/>\n\u251c\u2500\u2500\u2500apps<br \/>\n\u2502 &nbsp; \u251c\u2500\u2500\u2500app1<br \/>\n\u2502 &nbsp; \u2502 &nbsp; \u2502 &nbsp; models.py<br \/>\n\u2502 &nbsp; \u2502 &nbsp; \u2502 &nbsp; views.py<br \/>\n\u2502 &nbsp; \u2502 &nbsp; \u2502 &nbsp; urls.py<br \/>\n\u2502 &nbsp; \u2502 &nbsp; \u2502 &nbsp; ...<br \/>\n\u2502 &nbsp; \u2502<br \/>\n\u2502 &nbsp; \u251c\u2500\u2500\u2500app2<br \/>\n\u2502 &nbsp; \u2502 &nbsp; \u2502 &nbsp; models.py<br \/>\n\u2502 &nbsp; \u2502 &nbsp; \u2502 &nbsp; views.py<br \/>\n\u2502 &nbsp; \u2502 &nbsp; \u2502 &nbsp; urls.py<br \/>\n\u2502 &nbsp; \u2502 &nbsp; \u2502 &nbsp; ...<br \/>\n\u2502 &nbsp; \u2502<br \/>\n\u251c\u2500\u2500\u2500deployment<br \/>\n\u2502 &nbsp; \u2502 &nbsp; settings.py<br \/>\n\u2502 &nbsp; \u2502 &nbsp; urls.py<br \/>\n\u2502 &nbsp; \u2502 &nbsp; ...<\/div><\/div>\n<p>Now all you have to do is start the Django development server and access <code class=\"codecolorer text geshi\"><span class=\"text\">http:\/\/localhost:8000\/frontendapp\/<\/span><\/code> to get your Ember app.<\/p>\n<div class=\"codecolorer-container bash railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;\"><div class=\"bash codecolorer\"><span class=\"co4\">$ <\/span>python manage.py runserver<\/div><\/div>\n<h3>Wham Bam<\/h3>\n<p>There you have it! You now have an Ember app running alongside a Django app. Django can continue to serve up views and API endpoints all it wants and Ember will continue to do what it needs to do with all the client-side location routing. Pretty cool, right?<\/p>\n<p>If you have any questions, feel free to leave a comment. I&#8217;m pretty good about getting back to people.<\/p>\n<p>And seriously, I know that this is not ideal. But in particular use case, it works pretty great, and from what I&#8217;ve heard people ask, it&#8217;s more common of a problem than you&#8217;d think. I&#8217;m definitely open to hearing suggestions about how to improve this, but I&#8217;d say this is a good starting point.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Like a turducken or cherpumple, we&#8217;re going to stick Ember right into the guts of Django. Let&#8217;s get this out of the way: this is not ideal. Doing something like having Django power just the API through the Django REST Framework and then having Ember do all user-facing things would be smarter. Having the separation is easier for maintenance and clearly defines responsibilities. Unfortunately, real life is rarely ideal. Your website may have some static pages that necessarily need to be served away from the monolithic stature of Ember, but&#8230;<a class=\"read-more\" href=\"https:\/\/timothypoon.com\/blog\/2016\/02\/16\/ember-and-django-get-friendly\/\">read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":255,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[56,57,18,58,59],"class_list":["post-254","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-code","tag-django","tag-ember","tag-javascript","tag-python","tag-web-development","et-bg-layout-dark","et-white-bg"],"jetpack_featured_media_url":"https:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2016\/02\/ember-and-django-get-friendly.png","jetpack_shortlink":"https:\/\/wp.me\/p462yg-46","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/posts\/254","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/comments?post=254"}],"version-history":[{"count":9,"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/posts\/254\/revisions"}],"predecessor-version":[{"id":264,"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/posts\/254\/revisions\/264"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/media\/255"}],"wp:attachment":[{"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/media?parent=254"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/categories?post=254"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/tags?post=254"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}