แสดงบทความที่มีป้ายกำกับ file upload แสดงบทความทั้งหมด
แสดงบทความที่มีป้ายกำกับ file upload แสดงบทความทั้งหมด

วันจันทร์ที่ 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)