Делать несколько вызовов API и обновлять в цикле, используя Django
Я пытаюсь сделать вызов API и могу заставить его работать, когда я запрашиваю его с заданным входом (возвращая одну запись и делая вызов API для этой одной записи) из формы. Теперь, если ввод не предоставлен, я хочу перебрать все строки в фактической таблице и сделать вызовы API для любых отсутствующих столбцов данных...
Однако, когда я пытаюсь сделать несколько запросов на одной странице, при отправке формы, я не могу заставить вызов API работать, я получаю эту ошибку:
JSONDecodeError at / url Ожидаемое значение: строка 1, столбец 1 (символ 0) Метод запроса: POST URL-адрес запроса: http://localhost:8000/url Django Версия: 2.1.1 Тип исключения: JSONDecodeError Значение исключения:
Ожидаемое значение: строка 1, столбец 1 (символ 0) Местоположение исключения: C:\Users\AppData\Local\Programs\Python\Python37-32\Lib\json\decoder.py в raw_decode, строка 355 Исполняемый файл Python: C:\Users\.virtualenvs\ Projects\Scripts\python.exe
ОБНОВЛЕНИЕ: Это был сбой API, а не Django. Оставляя остальную часть вопроса в виде массовых обновлений, не работают
представления для вызова API:
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
Там нет URL для пользовательского метода..
путь ('api//', views.API.as_view(), name='a')
Мне нужно сделать этот вызов API из Django (так как вызовы основаны на том, что возвращено), поэтому я не могу использовать для этого Javascript или подход с использованием внешнего интерфейса.
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
})
ОБНОВЛЕНИЕ: Итак, я понял, что цикл работает нормально. Сбой API на второй записи, когда цикл проходил нормально. Однако многократное / массовое обновление для установки определенных столбцов с использованием данных, возвращаемых из API, не работает.
MyModel.objects.update(columToUpdate = apiData['field'])
не работает в цикле. Я подтвердил, что цикл вызывает обновление.
1 ответ
Всем, кто читает этот вопрос, обратите внимание, что я новичок в Django и, возможно, использую некоторые сомнительные практики. Тем не менее, все в коде в вопросе работает нормально, если вы думаете о нескольких вещах:
- Подумайте о крайних случаях, например, если API ничего не возвращает. Вернуть '' или None или что-то еще, а затем проверить, есть ли что-то возвращенное перед обработкой полей данных. Добавьте раздел исключений try, чтобы, если API действительно выдает ошибку, вы могли вернуть что-то обратно.
- Django.update не работает в цикле с разными значениями данных для одного и того же столбца, поэтому сделайте это вместо этого:
из транзакции импорта django.db
@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)