Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

How We Made Application Framework Using AngularJS and Django

DZone's Guide to

How We Made Application Framework Using AngularJS and Django

· Web Dev Zone
Free Resource

Start coding today to experience the powerful engine that drives data application’s development, brought to you in partnership with Qlik.

In the spring we had an idea to do a simple cloud backup service for Linux servers. Since then work on the project was carried out mainly in the evenings and on weekends, to expedite the process, it was decided to use only those technologies in which we have experience. For the backend-side was chosen Django, and the implementation of the client is often assumed as a SPA based AngularJS. The idea: to make the product with minimal functionality, and then gradually add new features. It was necessary to make flexible enough and scalable system. 

Routing

And the first question that arose was associated with routing in the client side. We needed a reliable and simple system that would support enclosed each other templates and unambiguously correlate a particular URL pattern desired. After a brief search, we chose ui-router.

Was approved by the following scheme:

By the way / user is shown Landing, which has no connection with the application. When switching to / app / file server gives app.html, which contains the entire head, all the scripts at the end of a single body and a div with a modest attribute ui-view. It is in this div is loaded all the application. Depending on user is logged in or not, it shows a different filling this div’a.

I will not get ahead of ourselves, and consider the case for the authenticated user. So, in this case in the URL after the / app / no hash inside <div ui-view> </ div> loaded next layer: index.html. This file have the static part of the application, which surrounds the entire working area: Header, footer and sidebar. In index.html also have a div with the attribute ui-view, which is loaded into another  application level - namely, the various screens (in this case: the main screen, the detailed screen of the server screen billing, backup and recovery the screen, etc.)

Let's see how this all described by ui-router:

app.config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider) {

    $stateProvider
        .state('index', {
            url: '/',
            templateUrl: '/static/views/index.html'
        })
        .state('index.main', {
            url: '^/main',
            templateUrl: '/static/views/pages/main.html'
        })
        .state('index.client', {
            url: '^/main/c/:id',
            templateUrl: '/static/views/pages/client.html'
        })
        .state('index.billing', {
            url: '^/billing',
            templateUrl: '/static/views/pages/billing.html'
        })
        .state('index.restore', {
            url: '^/restore',
            templateUrl: '/static/views/pages/restore.html'
        });

    $urlRouterProvider.otherwise('/main');  // If the hash does not match one, then redirect to the page / main
    
}])

Public and private pages

It is time to think about access rights of users to specific pages. If the user is not logged in, then it can only show the public pages, and when you try to approach the private page of his waiting Forced redirection to the login screen. So it is in the opposite direction: if the user has already entered, it will not be able to see the login page, registration and password recovery.

So, add data about public pages in the router configuration:

$stateProvider
    .state('login', {
        url: '/login',
        templateUrl: '/static/views/login.html'
    })
    .state('signup', {
        url: '/signup',
        templateUrl: '/static/views/signup.html'
    })
    .state('recovery', {
        url: '/recovery',
        templateUrl: '/static/views/recovery.html'
    });

In the module responsible for the authorization of a factory, which determines whether the user is logged in:

AuthModule.factory('Auth', ['$cookieStore', function ($cookieStore) {
    var currentUser = $cookieStore.get('login') || 0,
        publicStates = ['login', 'signup', 'recovery'];

    return {
        authorize: function(state) {
            return (this.isLoggedIn() && (publicStates.indexOf(state) < 0)) || (!this.isLoggedIn() && (publicStates.indexOf(state) >= 0))
        },
        isLoggedIn: function() {
            return !!currentUser;
        }
    }

}])

Is Logged In method returns true, if the user is logged in, or false otherwise. The method determines authorize for the current state, has a right to the user to be in it.

Use of these methods is done in the event handler $ stateChangeStart, which occurs at the beginning of changes in the state:

$rootScope.$on("$stateChangeStart", function (event, toState, toParams, fromState, fromParams) {
    // If the user has no right to be in this state
    if (!Auth.authorize(toState.name)) {
        // It is necessary to prevent further changes in the state
        event.preventDefault();
        // For the case of the primary ways of determining (when entering the / app / without hash)        
        if (fromState.url === '^') {
            if (Auth.isLoggedIn()) {
                $state.go('index.main');
            } else {
                $state.go('auth');
            }
        }
    }
});

Authentication

The authentication procedure on the client side is implemented using a factory Auth:

login: function (user, success, error) {
    $http.post('/login/', user)
        .success(function () {
            currentUser = 1;
            success();
        })
        .error(error);
}

Call this function is performed on the controller. The arguments are passed username, password and callbacks:

Auth.login({
    username: $scope.login.username,
    password: $scope.login.password
},
function () {
    $state.go('index.main');
},
function () {
    $scope.login.error = true;
});

On a server with standard django-sessions is stored user information (its id). It uses standard methods django.contrib.auth.

from django.contrib.auth import authenticate, login

def login_service(request):
    data = json.loads(request.body)
    user = authenticate(username=data['username'], password=data['password'])
    if user is not None:
        login(request, user)
        return HttpResponse(status=200)
    else:
        return HttpResponse('Login error', status=401)

During each http-request, the server checks whether the user is logged in, and sets in the header 'Set-Cookie' appropriate value. This value is checked in the client side using $ cookieStore.get (‘login').

Connection between the server and client models

In order to accelerate the development and increase the flexibility of the application, it was decided to use a middleware between Django and AngularJS. The choice fell on django-angular.

Its main advantages:

  • provides the ability to perform basic CRUD operations;
  • allows tight tie django-forms and angular-controllers;
  • provides functionality to call methods in django straight from angular-controller.

For more information about installing and configuring can be found in the documentation.

Create data driven applications in Qlik’s free and easy to use coding environment, brought to you in partnership with Qlik.

Topics:

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}