Django with Angular2 Tutorial


Django with Angular2 Tutorial - Getting Started

Django is awesome. Angular2 is also awesome. Many forums suggest that they both are awesome when there is abrupt seperation between them.

However need may arise to combine both django and angular2 to make your project double awesome.

I have come across a situation where I need to use angular2 and django side-by-side utilizing the features of both. To make it more complicated, requirement stated that angular application should be in the root url after login. It would have been bit easier if angular app is served from sub folder like domain.com/app/. Anyways, I wanted to find the solution (again, under critical deadline).

Download the source code HERE.

Project Setup

virtualenv /path/to/env/

cd /path/to/env/

source bin/activate

pip install django

django-admin startproject project_name

cd project_name/

python manage.py startapp app_name

python manage.py migrate

mkdir ngApp

cd ngApp

git clone https://github.com/angular/quickstart .

rm -rf .git/ .github/

mv index.html /path/to/django/app/templates/index.html

mv styles.css /path/to/django/app/static/css/styles.css

npm install

Now that we have succesfully setup our project directory.

In settings.py file

ANGULAR_URL = '/ng/'

ANGULAR_ROOT = os.path.join(BASE_DIR, 'ngApp/')

The above lines do same as static url and static root. Render static files inside ngApp/ directory.

Edit config in systemjs.config.js.

var config = {
map: map,
baseURL: '/ng/',
packages: packages
};

Note that baseURL: '/ng/' in the ANGULAR_URL

Now lets add some views in views.py.

class AngularApp(TemplateView):
  template_name = 'index.html'

  def get_context_data(self, **kwargs):
  context = super(AngularApp, self).get_context_data(**kwargs)
  context['ANGULAR_URL'] = settings.ANGULAR_URL
  return context

class SampleView(View):
	"""View to render django template to angular"""
	def get(self, request):
	return render("OK!")

Note that we are passing ANGULAR_URL as the context. This is to avoid hardcoding the path in the template.

Add the below in urls.py. ```python ngurls = [ url(r’^$’, SampleView.as_view(), name=’sample’), ]

urlpatterns = [ url(r’^admin/’, admin.site.urls), url(r’^(?!ng/).*$’, AngularApp.as_view(), name=”angular_app”), ] + static(settings.ANGULAR_URL, document_root=settings.ANGULAR_ROOT) ``` Here (?!ng/) is the ANGULAR_URL

Remember since you need the angular app in the root URL, you need to accept all the routing except static files in the ngApp. url(r'^(?!ng/).*$' does the same. It accepts all the paths except domain.com/ng/. This leaves you another challenge. If you route to domain.com/someurl/ , the above django route will show you to index.html, where you will have angular application. So, you have to handle 404 pages in angular application also.

Here comes the important part. We are using the django template to call the angular application. This is the place where you can make double awesome. You can add django logics here.

Now create index.html in templates folder under django app.

{% load static %}


<html>
  <head>
    <title>Angular 2 QuickStart</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="{% static 'css/styles.css' %}">
    <base href="/">
    <!-- Polyfill(s) for older browsers -->
    <script src="{{ ANGULAR_URL }}node_modules/core-js/client/shim.min.js"></script>
    <script src="{{ ANGULAR_URL }}node_modules/zone.js/dist/zone.js"></script>
    <script src="{{ ANGULAR_URL }}node_modules/reflect-metadata/Reflect.js"></script>
    <script src="{{ ANGULAR_URL }}node_modules/systemjs/dist/system.src.js"></script>
    <script src="{{ ANGULAR_URL }}systemjs.config.js"></script>

    {# -------------------------------------- #}
    {# Write your django logics anywhere here #}
    {# -------------------------------------- #}

    <script>
      window.STATIC_URL = "{{ ANGULAR_URL }}";
      System.import('/ng/app/main').catch(function(err){
          console.error(err);
      });
    </script>
  </head>
  <body>
    <my-app>Loading...</my-app>
  </body>
</html>

In System.import you should specify /ANGULAR_URL/angular_app_folder/name_of_main.

For example, if you have two angular applications based on user roles, you can set a condition here and route them accordingly by changing in System.import. Or you can display the name and profile picture current user in the template or something similar to stackoverfow reputation of current user but remember you can handle it in angular also. One thing you should keep in mind is that if you are using the above model, keep login and registration as a pure django template.

Now create the following files.

main.ts

import { bootstrap }    from '@angular/platform-browser-dynamic';

import { AppComponent } from './app.component';
import {appRouterProviders} from "./app.route";
import {HTTP_PROVIDERS} from "@angular/http";
import {enableProdMode} from '@angular/core';

enableProdMode();
bootstrap(AppComponent, [
  appRouterProviders,
  HTTP_PROVIDERS
])
.catch(err => console.error(err));

cd app

Lets add two more components to implement routing.

app.route.ts

import { provideRouter, RouterConfig } from '@angular/router';
import {Component1Component} from "./component1.component";
import {Component2Component} from "./component2.component";

const routes: RouterConfig = [
	{ path: '',redirectTo: '/component1',pathMatch: 'full'},
  { path: 'component1', component: Component1Component },
  { path: 'component2', component: Component2Component },
];

export const appRouterProviders = [
  provideRouter(routes)
];

app.component.ts

import { Component } from '@angular/core';
import { ROUTER_DIRECTIVES } from '@angular/router';

@Component({
    selector: 'my-app',
    template: `
        <h1>My First Angular 2 App</h1>
        <nav>
          <a routerLink="/component1" routerLinkActive="active">Component 1</a>
          <a routerLink="/component2" routerLinkActive="active">Component 2</a>
        </nav>
        <router-outlet></router-outlet>
    `,
    directives: [ROUTER_DIRECTIVES]
})
export class AppComponent { }

component1.component.ts

import {Component} from "@angular/core";
@Component({
  template: '<h1>Component 1</h1>'
})
export class Component1Component{

}

component2.component.ts

import {Component} from "@angular/core";
@Component({
  template: '<h1>Component 2</h1>'
})
export class Component2Component{

}

Now your folder structure should look something like this. I have included all the files in the tree below.

.
├── core
│   ├── admin.py
│   ├── apps.py
│   ├── __init__.py
│   ├── migrations
│   │   ├── __init__.py
│   ├── models.py
│   ├── static
│   │   └── css
│   │       └── styles.css
│   ├── templates
│   │   └── index.html
│   ├── tests.py
│   ├── views.py
├── project
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   ├── wsgi.py
├── db.sqlite3
├── LICENSE
├── manage.py
├── ngApp
│   ├── app
│   │   ├── app.component.spec.ts
│   │   ├── app.component.ts
│   │   ├── app.route.ts
│   │   ├── component1.component.ts
│   │   ├── component2.component.ts
│   │   └── main.ts
│   ├── CHANGELOG.md
│   ├── Dockerfile
│   ├── e2e
│   ├── node_modules
│   │   ├
│   ├── README.md
│   ├── typings
│   │   ├── 
└── README.md
cd /path/to/ngApp/

npm start 

Open a new terminal,

cd path/to/django-ng2-starter/

python manage.py runserver

Now visit localhost:8000 in your browser. You need NPM runing in another terminal during development phase to compile typescript into javascript as you are making changes.


UPDATE: Follow up of this tutorial Django with Angular2 Tutorial - Part 2 - Rendering templates is focused on rendeing Django context variables and Jinja2 context variables in the same template file without any conflicts.

Happy Coding :)


Related Posts

Python Month workshop in Chennai

Experiences with students during python workshop

Django with Angular2 Tutorial -part 2

Rendering template with Django and Angular2.

Hello World !!!

About this awesome blog.