Make multiple API calls and update in a loop using Django

3.4k Views Asked by At

I am trying to make an API call and am able to get it working when I request it with a given input (so returning one record, and making the API call on that one record) from a form. Now, if the input is not provided I want to loop through all rows in the actual table, and make API calls for any missing data columns...

However, when I try to make multiple requests on the same page, on form submit, I can't get the api call to work, I get this error:

JSONDecodeError at /url Expecting value: line 1 column 1 (char 0) Request Method: POST Request URL: http://localhost:8000/url Django Version: 2.1.1 Exception Type: JSONDecodeError Exception Value:
Expecting value: line 1 column 1 (char 0) Exception Location: C:\Users\AppData\Local\Programs\Python\Python37-32\Lib\json\decoder.py in raw_decode, line 355 Python Executable: C:\Users\.virtualenvs\projects\Scripts\python.exe

UPDATE: This was the API failing, not Django. Leaving the rest of the question in as bulk updates do not work

views to make the API call:

class API(View):
  def get(self, request, *args, **kwargs):

    url = 'https://ExternalAPI/{param1}'.format(param1=param1)
    response = requests.get(url, headers={'x-Key': settings.KEY})

    if response.status_code == 404:
        return JsonResponse({})

    return JsonResponse(response.json()[0])

# Works for 1 row, doesn't work when called within a loop from a form submission....
  def getAnotherAPICall(self, request, address):
    print('getting data...')
    response = requests.get('{}?param={}&id={}'.format(settings.URL, data, settings.ID))
    data = response.json()  
    result = data['Response'][0] # This is based on the API itself....

    if response.status_code == 404:
      return {}

    return result

There is no URL for the custom method..

path('api//', views.API.as_view(), name='a')

I need to make this API call from within Django (as the calls are based on what's returned) so I cannot use Javascript or a frontend approach for this..

class MyView(TemplateView):
    def post(self, request):
        form = MyForm(request.POST)
        formIDInput = form.cleaned_data['formIDInput']
        apiData = []
            if form.is_valid():
               if(formIDInput):
                    resultQuerySet = MyModel.objects.filter(PrimaryID= str(formIDInput)) # One row, API call works
                else 
                    resultQuerySet = MyModel.objects.all()              #Multiple rows, API call doesn't work when API call is made

                 for result in resultQuerySet:
                          # This step fails:
                          apiData  = API.getAnotherAPICall(self, request, result.column1) # result.column1 is parameter to make the API call...

                        apiData.append({
                            'ID': result.PrimaryID,
                            'Data': apiData
                        })
                            MyModel.objects.update(columToUpdate = apiData['field'])

        return render(request, 'template.html', {
            'form': form,
            'results': resultQuerySet
        })

UPDATE: So, I figured out the loop runs just fine. The API was failing on the second record, when the loop was going through just fine. However, multiple/bulk updates to set specific columns using the data returned from the API, doesn't work.

MyModel.objects.update(columToUpdate = apiData['field'])

doesn't work in a loop. I verified the loop does call the update.

1

There are 1 best solutions below

0
On BEST ANSWER

To anyone else reading this question, note that I'm a Django novice and maybe using some questionable practises. However, everything on the code in the question works fine, as long as you think of a few things:

  • Think of edge cases, for instance if the API doesn't return anything. Return '' or None or something and then check if there's something returned before processing the data fields. Add a try exception section so if the API actually errors out, you can return something back.
  • Django .update doesn't work in a loop with different data values for the same column, so do this instead:

from django.db import transaction

@staticmethod

def updateBulk(id, newValue):
    rows = MyModel.objects.filter(id=id)

    transaction.set_autocommit(False)
    for row in rows:
            row.column1 = newValue

        row.save()
    transaction.commit()
    transaction.set_autocommit(True)