2

Follow up onto:

AutoField should be present but it's not (django)?

related to:

"Cannot update a query once a slice has been taken". Best practices?

I don't need to filter objects, only order by date and select the most recent one:

def get_latest_currency(self):
    """
    Return most up to date value
    """
    up_to_date_currency = Currency.objects.order_by('-currency_value_in_dollars_date')[:1]

    if not up_to_date_currency.exists():
        # No objects yet; fetch currencies
        update_coins_table()

    return Currency.objects.order_by('-currency_value_in_dollars_date')[:1]

up_to_date_currency is initialized correctly; the last line gives:

    assert not self.query.is_sliced, \
AssertionError: Cannot filter a query once a slice has been taken.

This code represents a view (I want to return a plain JSON object (this is a REST endpoint)). Why is django complaining about a filter when only a slice was used?

get_latest_currency is the name of the endpoint:

import sys

from django.urls import path
from . import views

app_name = 'manage_crypto_currency'
urlpatterns = [
    path('get_currency/', views.get_latest_currency, name='index'),
]

Stacktrace:

Internal Server Error: /get_currency/
Traceback (most recent call last):
  File "C:\projects\crypto-currency-board\venv\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
    response = get_response(request)
  File "C:\projects\crypto-currency-board\venv\lib\site-packages\django\utils\deprecation.py", line 116, in __call__
    response = self.process_response(request, response)
  File "C:\projects\crypto-currency-board\venv\lib\site-packages\django\middleware\clickjacking.py", line 26, in process_response
    if response.get('X-Frame-Options') is not None:
  File "C:\projects\crypto-currency-board\venv\lib\site-packages\django\db\models\query.py", line 418, in get
    clone = self._chain() if self.query.combinator else self.filter(*args, **kwargs)
  File "C:\projects\crypto-currency-board\venv\lib\site-packages\django\db\models\query.py", line 942, in filter
    return self._filter_or_exclude(False, *args, **kwargs)
  File "C:\projects\crypto-currency-board\venv\lib\site-packages\django\db\models\query.py", line 954, in _filter_or_exclude
    assert not self.query.is_sliced, \
AssertionError: Cannot filter a query once a slice has been taken.

Tried wrapping the objects around HttpReponse():

return HttpResponse(Currency.objects.order_by('-currency_value_in_dollars_date')[:1], content_type='application' '/json')

This works but only the name is, for some reason, returned.

Sebi
  • 4,262
  • 13
  • 60
  • 116

1 Answers1

1

You are returning a QuerySet as result of a view, but a view can not return a QuerySet. The middleware aims to convert this in a HTTP response hence the error.

Your view thus needs to return some HttpResponse [Django-doc]. A very simple response would be the str(…) of the QuerySet:

def get_latest_currency(self):
    up_to_date_currency = Currency.objects.order_by('-currency_value_in_dollars_date')[:1]

    if not up_to_date_currency.exists():
        # No objects yet; fetch currencies
        update_coins_table()

    qs = Currency.objects.order_by('-currency_value_in_dollars_date')[:1]
    # …
    return HttpResponse(str(qs))

You can of course return a more sophisticated result, for example by rendering a template, or returning the result of a serializer.

FOr example if you want to serialize the last object, you can use:

from django.http import JsonResponse
from django.core.serializers import serialize
from json import loads as jloads

def get_latest_currency(self):
    up_to_date_currency = Currency.objects.order_by('-currency_value_in_dollars_date')[:1]

    if not up_to_date_currency.exists():
        # No objects yet; fetch currencies
        update_coins_table()

    cr = Currency.objects.latest('-currency_value_in_dollars_date')
    data = serialize('json', [cr])
    return JsonResponse({'data' : jloads(data)})
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • When using str(query_results) I get ]> . – Sebi Nov 22 '20 at 14:27
  • 1
    @Sebi: yes exactly, but the point is you can *not* return a `QuerySet` as result of a view. A HTTP response is always *text*, so you can for example serialize it to a JSON blob, etc. but you can not return a `QuerySet`, model object, etc. – Willem Van Onsem Nov 22 '20 at 14:28
  • 1
    @Sebi: you can use the `JsonResponse` and the Django serialize to JSON serialize the data. – Willem Van Onsem Nov 22 '20 at 14:41