2

I'm building a rather simple CRM using the Flask Python framework. I have a database of companies that we are interested in contacting. The user first inputs how many companies they would like to contact. The user is then redirected to this page:

CRM First Screen

Essentially for each row/company on this page, the user will click either the contact or don't contact radio button.

What I am trying to accomplish

Once the user clicks the 'Let the Magic Happen' button at the bottom, JavaScript runs through each row and sees which button is clicked. It then appends the database unique ID to one of two arrays, 'contact' and 'remove'. This information then gets passed along to python via getJSON, python captures the json data using request.args.get.

Finally, Python does one of two things:

  • for the companies in the remove array, it changes a bool value in the respective database instance
  • for the companies in the contact array, it runs a separate function which uses SMTP to email that company

Where I am getting hung up

I can't seem to retrieve the json data in Python, I am trying to just do a simple print statement as of right now to show that I can pull in the data.

Also, would it be more efficient in terms of performance to have the javascript send each row to python individually or all at once in an array?

Scripts

app.py

@app.route('/send_emails')
def send_emails():
  contact = request.args.get('contact')
  remove = request.args.get('remove')

  print contact
  print remove

  return ('', 204) #No need to return anything

email.js

$('#batch-page .magic-button').click( function() {

  //Iterate over each company row
  $('#batch-page table tr.company-row').each(function(i, company){
    company = $(company);
    company_id = company.attr('class').split(' ')[1];

    //Assign arrays for emailing and removing comapnies
    var contact = [];
    var remove = [];

    //Check to see whether the contact or don't contact checkbox is checked
    if(company.children('td.contact-company').children('input').is(':checked')) {
      contact.push(company_id);
    } else if (company.children('td.remove-company').children('input').is(':checked')) {
      remove.push(company_id);
    }

    //Pass the data along to Python
    $.getJSON('/send_emails', {
      contact: contact,
      remove: remove
    });
  });
  $('div#batch-page').html('<p>Be patient, contacting companies!</p>');
});

batch.html

  {% for company in companies %}
    <tr class="company-row {{ company.id }}">
      <td class="company-name">
        <p>{{ company.company_name }}</p>
      </td>
      <td class="company-website">
        <div>
          <a href="{{ company.website }}" target="blank_">{{ company.website }}</a>
        </div>
      </td>
      <td class="company-email">
        <p>{{ company.email_address }}</p>
      </td>
      <td class="contact-company">
        <input type="checkbox" class="contact" for='{{ company.id }}'>
      </td>
      <td class="remove-company">
        <input type="checkbox" class="dont-contact" for='{{ company.id }}'></td>
      <td>
        <a class="btn btn-primary" data-toggle="collapse" data-target="#{{ company.id }}-info">Change Company Information</a>
      </td>
    </tr>
    <tr class="company-info-row">

      <td colspan="6" class="hiddenRow">
        <div class="accordion-body collapse" id="{{ company.id }}-info">
          <form action="" id="{{ company.id }}-edit-form" method="POST" class="update-company-form">
            <input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
            <div class="col-md-4">
              <div class="form-group">
                <label for="{{ company.id }}-company-name">Company Name</label>
                <input type="text" value="{{ company.company_name }}" id="{{ company.id }}-company-name" class="form-control" name="company-name">
                <label for="{{ company.id }}-company-website">Company Website</label>
                <input type="text" value="{{ company.website }}" id="{{ company.id }}-company-website" class="form-control" name="company-website">
              </div>
            </div>
            <div class="col-md-4">
              <div class="form-group">
                <label for="{{ company.id }}-email-address">Company Email</label>
                <input type="text" value="{{ company.email_address }}" id="{{ company.id }}-email-address" class="form-control" name="company-email">
              </div>
              <div class="form-group">
                <input type="submit" form="{{ company.id }}-edit-form" class="btn btn-default" value="Update">
              </div>
            </div>
            <div class="col-md-4 ajax-message">
              <div>
                <i class="fa fa-clock-o fa-2x"></i>
                <p style="display: inline-block;">Date scraped on: {{ company.scraped_on }}</p>
              </div>
            </div>
          </form>
        </div>
      </td>
    </tr>
  {% endfor %}

Update #1

Tried using the loads method from the json module to load in the request, I am getting the following error message:

Traceback (most recent call last):
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/wyssuser/Desktop/dscraper/app.py", line 82, in send_emails
    content = json.loads(request.json)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py", line 338, in loads
    return _default_decoder.decode(s)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.py", line 365, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
TypeError: expected string or buffer
Joey Orlando
  • 1,408
  • 2
  • 17
  • 33
  • possible duplicate of [How to get POSTed json in Flask?](http://stackoverflow.com/questions/20001229/how-to-get-posted-json-in-flask) – Celeo Jun 15 '15 at 20:56
  • I don't think its a duplicate. This is using GET not POST, although the might be better serverd using POST – junnytony Jun 17 '15 at 20:22

3 Answers3

3

First of all jQuery.getJSON() issues a GET request using the JSON object you pass it as query parameters.

The problem here is that jQuery.getJSON() serializes the lists in a non traditional way. So if you looked at the request received sent by the browser it would look something like:

http://example.com/?contact[]=me&contact[]=others&contact[]=hr&remove[]=you&remove[]=doug

Now, Flask will parse that querystring into an args dict that has the keys contact[] and remove[] but since you're doing `request.args.get('contact'), you get nothing

The solution is to create the query parameters yourself before passing to jQuery.getJSON() like this. This can be done using jQuery.param():

//Assign arrays for emailing and removing companies
var contact = ["me", "others", "hr"];
var remove = ["you", "doug"];

//Pass the data along to Python
$.getJSON(
    '/send_emails',
    $.param({ contact: contact, remove: remove }, true)
);

Note the true passed to jQuery.param(), it returns the querystring in the traditional format which looks like this:

contact=me&contact=others&contact=hr&remove=you&remove=doug

Now, you can retrieve your parameters in Flask using

contacts = request.args.getList('contact')
print(contacts) # ['me', 'others', 'hr'] 
junnytony
  • 3,455
  • 1
  • 22
  • 24
  • do i need to encrypt the JSON, or will an SSL certificate take care of it like everything else in flask – Arjun Sep 22 '19 at 22:32
  • As long as you're using https (SSL or TLS) encryption happens automatically at the connection layer so no need to encrypt anything. – junnytony Oct 22 '19 at 13:54
1

you need to get the json from the request,

content = request.json

Then using your favorite json parser parse the json into an object.

obj = json.loads(content)

To answer your question, "would it be more efficient in terms of performance to have the javascript send each row to python individually or all at once in an array?", it would be more efficient to send all of the data at once and return one return.

cfraschetti
  • 127
  • 1
  • 6
  • I tried this but I am getting an error message basically saying that the json is not a 'string or buffer' – Joey Orlando Jun 15 '15 at 20:10
  • When you access your webapi from javascript you need to make sure you are setting your headers. You need Content-Type="application/json" otherwise the json part of the request will not be set. You should also add Accepts: "application/json" for your return type. – cfraschetti Jun 16 '15 at 11:36
  • $.getJSON issues a `GET` request with the data passed to it as a querystring so there will be nothing in `request.json` – junnytony Jun 17 '15 at 20:23
-1

There is a typo: contacts = request.args.getList('contact'). I think you would have written contacts = request.args.getlist('contact').