Ember and Django Get Friendly
Like a turducken or cherpumple, we’re going to stick Ember right into the guts of Django.
Let’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 in keeping assets reusable, they’re still tied into the front end builds. Or you may have deployment requirements that necessitate keeping this tightly bundled. Either way, we’re here now, so let’s figure it out.
The Django Part
Getting Django set up is fairly straightforward, as prescribed by the Django docs. The basics on OS X go something like this.
$ brew install pyenv # Additional steps at https://github.com/yyuu/pyenv#homebrew-on-mac-os-x
$ pyenv virtualenv --python=$(which python3) myenv
$ pyenv activate myenv
$ pip install Django==1.9.2
$ django-admin startproject myapp
$ cd myapp/
$ python manage.py startapp app1
This will install Python 3.x and pyenv, create a virtualenv called myenv
, install Django v1.9.2 to it, and then create a skeleton project in the myapp
directory with a single app1
application.
I like to structure my Django projects a particular way since they tend to have multiple apps but a singular source of deployment settings.
│ manage.py
│ ...
│
├───apps
│ ├───app1
│ │ │ models.py
│ │ │ views.py
│ │ │ ...
│ │
│ ├───app2
│ │ │ models.py
│ │ │ views.py
│ │ │ ...
│ │
├───deployment
│ │ settings.py
│ │ urls.py
│ │ ...
This does require some changes to fit into this new structure, however.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # manage.py L6 os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'deployment.settings') # /deployment/settings.py INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'apps.app1', 'apps.app2', ] ROOT_URLCONF = 'deployment.urls' |
And remember that you’ll now be doing imports like from apps.yourapp import models
instead of from yourapp import models
.
The Ember Part
The cool part about Ember these days is Ember CLI, which facilitates a great deal of abiding the framework’s directory requirements. We’ll continue with getting that all set up.
$ npm install -g ember-cli
$ npm install -g bower
$ brew install watchman
$ npm install -g phantomjs
$ ember new frontendapp
If you’re using Git for source control (and you should be, you dummy), this will create a separate Git repo inside /frontendapp/.git
, so you might want to remove that.
And if you’re using Submline Text as a text editor, the Ember CLI user guide has a good tip about performance.
Hooking It All Up
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.
$ ember serve --output-path ../static/ --live-reload=false
By running this during development, you’ll get the constant Ember builds being thrown into static/
without the live reload feature since that’s unnecessary with what we’re doing.
Next you’ll want to edit the deployment/settings.py
file to get Django to serve the static files properly.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [ os.path.join(BASE_DIR, 'templates'), os.path.join(BASE_DIR, 'static'), ], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] STATIC_URL = '/static/' STATICFILES_DIRS = ( os.path.join(BASE_DIR, 'static'), ) |
And now we’ll get Ember to look in the right places. We’ll be using ember-cli-replace to manage environment replacements.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | // frontendapp/package.json { ... "devDependencies": { ... "ember-cli-replace": "0.2.1" } } // frontendapp/config/environment.js var ENV = { ... baseURL: '/frontendapp/', apiURL: '/api' }; // frontendapp/ember-cli-build.js module.exports = function(defaults) { ... var replacements = { assetsURL: '/static/assets', imagesURL: '/static/images', }; for (var key in replacements) { app.options.replace.patterns.push({ match: key, replacement: replacements[key], }); } |
So now you can use @@assetURL
and @@imagesURL
in place of hardcoding URLs in frontendapp/app/index.html
. (And don’t forget to rerun npm install
.)
1 2 3 4 5 |
If you have app1
deal with all the Django-based pages and app2
act as the API, you can set up the various urls.py
files to take care of everything.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # deployment/urls.py urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^', include('apps.app1.urls')), url(r'^api/', include('apps.app2.urls')), ] # apps/app1/urls.py urlpatterns = [ url(r'^$', views.index, name='index'), url(r'^frontendapp/', views.frontendapp, name='frontendapp'), ] # apps/app1/views.py def index(request): return render(request, 'main.html') def frontendapp(request): return render(request, 'index.html') # apps/app2/urls.py urlpatterns = [ url(r'^persons/(?P<game_id>[^/]+)?', views.persons, name='persons'), url(r'^places/(?P<team_id>[^/]+)?', views.places, name='places'), url(r'^things/(?P<bracket_id>[^/]+)?', views.things, name='things'), ] |
The resulting directory and file structure should look something like this once you have Ember building and whatnot.
│ manage.py
│ ...
│
├───frontendapp
│ │ package.json
│ │ ember-cli-build.js
│ │ ...
│ │
│ ├───config
│ │ │ environment.js
│ │
│ ├───app
│ │ │ index.html
│ │ │ app.js
│ │ │ router.js
│ │ │ ...
│ │ │
│ │ ├───styles
│ │ ├───templates
│ │ └───...
│ │
│ ├───public
│ └───...
│
├───static
│ │ index.html
│ │ ...
│ │
│ ├───assets
│ ├───images
│ └───...
│
├───templates
│ │ main.html
│ │ ...
│
├───apps
│ ├───app1
│ │ │ models.py
│ │ │ views.py
│ │ │ urls.py
│ │ │ ...
│ │
│ ├───app2
│ │ │ models.py
│ │ │ views.py
│ │ │ urls.py
│ │ │ ...
│ │
├───deployment
│ │ settings.py
│ │ urls.py
│ │ ...
Now all you have to do is start the Django development server and access http://localhost:8000/frontendapp/
to get your Ember app.
Wham Bam
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?
If you have any questions, feel free to leave a comment. I’m pretty good about getting back to people.
And seriously, I know that this is not ideal. But in particular use case, it works pretty great, and from what I’ve heard people ask, it’s more common of a problem than you’d think. I’m definitely open to hearing suggestions about how to improve this, but I’d say this is a good starting point.
An outstanding share! I have just forwarded this onto a colleague who was doing a little homework on this. And he in fact bought me dinner because I stumbled upon it for him… lol. So allow me to reword this…. Thank YOU for the meal!! But yeah, thanx for spending some time to talk about this issue here on your blog.
The software says exclusively relevant. Each of reduced attributes happen to be formulated with various capture certification. I like the application many
https://www.medyum.best/
oyun indir
you are really a good webmaster. The website loading speed is amazing. It seems that you’re doing any unique trick. Furthermore, The contents are masterwork. you’ve done a wonderful job on this topic!
wso shell
Merely a smiling visitant here to share the love (:
Your content is good, I like it. I’ll visit it again sometime. thank you