วันจันทร์ที่ 21 ตุลาคม พ.ศ. 2556

Passing Request from AngularJS to Django

transform POST data before send from Angular to Django (with array of object)

// NOTE: this 2 lines for Django to receive POST data
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
$httpProvider.defaults.transformRequest = function(data) {
   if (data === undefined) {
      return data;
   }
   // NOTE: if transform this way -> at Django use json.loads(request.body)
   // can support array of object (no need to use getlist() at Django side)
   return JSON.stringify(data);
   // NOTE: if transform this way -> at Django use request.POST['key']
   // array of object will be sent with key like 'rows[10][id]', 'row[10][revenue]'
   // need to parse at Django side
// return $.param(data);
}

Passing Django's CSRF token through AngularJS

option 1:
var csrf_token = $('input[name="csrfmiddlewaretoken"]').val();
$http.post("/import_actual_simple_xls", postData, {
    headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', "X-CSRFToken" : csrf_token},
}).success(function(data, status, headers, config) {
    //other things to do when success

    ...
});

option 2:
ImportControllers.config(['$httpProvider', function($httpProvider) {
    // NOTE: this 2 lines for Django's csrf_token   

    $httpProvider.defaults.xsrfCookieName = 'csrftoken';
    $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
}]);

AngularJS - Any way for $http.post to send request parameters instead of JSON?

When post data using AngularJS' $http or $http.post(),
at Django side, request.POST is an empty dict but request.body has JSON string.

Use method in this page to transform request data JSON string --> request data parameter,
e.g.
{"param1":"value1","param2":"value2","param3":"value3"} --> param1=value1&param2=value2&param3=value3

Set up global transformRequest function:

var app = angular.module('myApp');

app.config(function ($httpProvider) {
    $httpProvider.defaults.transformRequest = function(data){
        if (data === undefined) {
            return data;
        }
        return $.param(data);
    }
});

Sample non-global transformRequest per call:

var transform = function(data){
    return $.param(data);
}


$http.post("/foo/bar", requestData, {
    headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
    transformRequest: transform
}).success(function(responseData) {
    //do stuff with response

    ....});

For Hidden Field to Send Form Data

use <input name="stock_code" type="hidden" value="{{ actual.code }}">

Excel File Upload

After spending THE WHOLE DAY surfing internet, trying to find the way to send form data (including uploaded file) from AngularJS front-end to Django backend, here are what I get.
jQuery Form is my HERO.
My solution here is
- use jQuery Form to submit form data and file upload to backend.
- use dataType: 'html' for option passed to jQuery Form (I didn't know why but 'xml' didn't work).
- pass callback function to jQuery Form to update models when got response back.
- in the callback function, use $scope.$apply() to force AngularJS refresh its model after posted.
- no progress bar, no upload multiple files here because I don't need it now, but I really appreciate if you could guide me how to do.
NOTE: an example of upload progress here >> http://jquery.malsup.com/form/progress.html

html part (sample form which has both primitive data (multiplier) and file upload (input_excel))

<div id="div_load_xls" class="user-form col-lg-8" ng-app='myApp' ng-controller='importXlsController'>

    <form id="frm_load_xls" ng-submit='submitXls()' class="form-horizontal" method="post">

    {% csrf_token %}

        <input id="id_multiplier" name="multiplier" type="text" />

        <input id="id_input_excel" name="input_excel" type="file" />

        <input type="submit" name="validate_simple_actual" value="Validate" />

    </form>

</div>


Javascript part


<script src='/static/lib/js/angular-1.0.8.js'></script>    
<script src='/static/lib/js/jquery.form.js'></script>    

<script language="javascript" type="text/javascript">

    // get CSRF token from form's hidden field (generated from {% csfr_token %})

    var csrf_token = $('input[name="csrfmiddlewaretoken"]').val();

    // define AngularJS module and controller
    var myAppModule = angular.module('myApp', []);
    myAppModule.controller('importXlsController', importXlsController);

    // controller definition
    function importXlsController($scope, $http) {
        // function called when click submit button (ng-submit in the above form)
        $scope.submitXls = function() {

         // submit options
         var options = {
            dataType: 'html', // don't know why, but I used 'xml' and it didn't work
            url: '/import_actual_simple_xls', // to Django backend
            success: $scope.showResponse // callback function to process response defined below
         }

         // submit form data
         $('#frm_load_xls').ajaxSubmit(options);
      };

      // callback function to process response
      $scope.showResponse = function(responseText, statusText, xhr, $form) {
          // update model fields
          // use $apply to force AngularJS view to refresh
          $scope.$apply( function() {
               $scope.messages = jQuery.parseJSON(responseText);
         });
        };
    };

</script>


django backend (urls.py omitted)

def import_actual_simple_xls(request):
    // read primitive form data

    mul = request.POST.get('multiplier', None)

    if mul:
        messages.append('multiplier = %s' % mul)
    else:
        messages.append('No multiplier')

    // get file uploaded (handle error if needed)
    input_excel = request.FILES.get('input_excel', None)
    if not input_excel:
        messages.append('No Xls')
    else:
        book = xlrd.open_workbook(file_contents=input_excel.read())
        if ('Question List' in book.sheet_names()):
            messages.append('xls OK')
        else:
            messages.append('xls NG')
    return JSONResponse(messages)

ไม่มีความคิดเห็น:

แสดงความคิดเห็น