简体   繁体   中英

Flask - Getting JavaScript and Python to Communicate

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第一屏

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

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'] 

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM