Save query string data using rest framework in Django - python

I need to save to a database the query string data coming from a GET request using Django Rest framework.
Something like this:
URL: "http://127.0.0.1:8000/snippets/snippets/?longitude=123123&latitude=456456"
class SnippetList(generics.ListCreateAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
#code here for saving the query string data to database, in this case save:
#{
#"longitude":123123,
#"latitude":456456
#}
It's just like saving the params data like it were a POST request.

I need to save to a database the query string data coming from a GET request using Django Rest framework.
This is against the specifications of the HTTP protocol. Indeed, a GET request should only be used to retrieve data, not update data. For that a POST, PUT, PATCH or DELETE request should be used. The querystring is normally used to filter, not to store data.
If you really want to do this, you can override the .get(…) handler and
# Warning: against the HTTP protocol specifications!
class SnippetCreateView(generics.CreateAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
# {
# "longitude":123123,
# "latitude":456456
# }
def get(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.query_params)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(
serializer.data, status=status.HTTP_201_CREATED, headers=headers
)
But this is really not a good idea.

Related

Validate form data and query params in one serializer in APIView in django rest framework

I am using django rest framework for my web API. In my post API I need both the form data and the query params from the request and pass it to serializer for validation. To achieve this I am doing this:
version = request.query_params.get('version', 'v1')
serializer = MySerializer(
data=request.data, context={'version': version})
and in the serializer I am accessing it like this:
version = serializers.CharField(required=False, default='v1')
and then accessing it in my APIView as:
if serializer.is_valid():
data = serializer.validated_data
print("version: ", data['version'])
Even if I pass v2 as the query params it always prints v1. What am I doing wrong here?
I think you can try this:
sent_data = {
**request.data,
**request.query_params,
}
serializer = YourSerializer(data=sent_data)
serializer.is_valid(raise_exception=True)
Or if you want to only pass version query param to serializer, you can do this:
sent_data = {
**request.data,
"version": request.query_params.get("version", "v1"),
}
serializer = YourSerializer(data=sent_data)
serializer.is_valid(raise_exception=True)

Celery EncodeError(TypeError('Object of type Response is not JSON serializable'))

I am using Celery - Redis - Django rest framework together.
The error happens when I try to pass the serializer to the delay of celery within the Django rest framework.
Here is the viewset
class TestSet(viewsets.ModelViewSet):
queryset = Test.objects.all()
serializer_class = ImageSerializer
def create(self, request, *args, **kwargs):
serializer = TestSerializer(data=request.data)
if serializer.is_valid():
image_uploaded= "static_path"
json_data = base64.b64encode(np.array(image_uploaded)).decode('ascii')
result = test_call.delay({'image': json_data})
result = test_call.delay(serializer)
data = {"task": result.task_id}
return Response(data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
#shared_task(name="values")
def test_call(decoded_image):
return decoded_image
The error I get is
EncodeError(TypeError('Object of type Response is not JSON
serializable'))
Update:
Even when I do this, I still get an error
result = test_call.delay({"task": 1})
#shared_task(name="values")
def test_call(decoded_image):
return {"task": 2}
This isn't going to answer your question, but I can't leave a comment (low reputation).
It seems that you are trying to JSON Serialize something that obviously isn't JSON serializable. Based on the name, it is some kind of image data. You could try a different workflow that should be JSON Serializable, example:
One Example:
first save the image somewhere that is accessible later and add the location in the serializer (S3 bucket and then a link to the image)
In your celery task, fetch the image data based on that location
Second Example:
convert the image data into something JSON serializable like a Base64 image string

Caching must be implemented at view level, in models or in serializers in Django

I have a web application purely based on REST API using Django Rest Framework. I have seen that at most of the places the response for my APIs is not changing or not changing frequently, so I'm thinking to cache such API's and for that, I'm using https://pypi.org/project/redis/ package. So my question here is what could be the better way to implement caching, it should be at the view level, at the model level, or in the serializer. How it could be done?
You can use Cache for APIview and ViewSets with decorators like cache_page.
NOTE: The cache_page decorator only caches the GET and HEAD responses with status 200.
Ex:
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
class UserViewSet(viewsets.ViewSet):
# Cache requested url for each user for 2 hours
#method_decorator(cache_page(60*60*2))
def list(self, request, format=None):
content = {
'user_feed': request.user.get_user_feed()
}
return Response(content)
Or
class PostView(APIView):
# Cache page for the requested url
#method_decorator(cache_page(60*60*2))
def get(self, request, format=None):
content = {
'title': 'Post title',
'body': 'Post content'
}
return Response(content)
DRF cache docs.
settings.py:
# Enable memcache
# https://devcenter.heroku.com/articles/memcache#using_memcache_from_python
CACHES = {
'default': {
'BACKEND': 'django_pylibmc.memcached.PyLibMCCache'
}
}
If you want store just result of a method or a query and store for furture requests, you can just define a key for it and set that result to that key with cache.set(cache_key, result, expire_time) and then get it(cache.get(cache_key)) whenever you want.
Remember you should define a cache backend for your results.Proper and better solution is to use message brokers like redis or memcached to store cache.based on your needs.
//Updated//
check if data is already cashed or not.
class WeatherView(APIView):
def get(self):
if(cache.get('weatherdata') == None):
url = 'https://api.openweathermap.org/data/2.5/forecast?q=' + '...';
serialized_data = urlopen(url).read()
data = json.loads(serialized_data)
print(data)
cache.set('weatherdata', data, 3600)
else:
data = cache.get('weatherdata')
serializer_class = WeatherSerializer(data)
responseJSON = JSONRenderer().render(serializer_class.data)
return Response(responseJSON)

How can I GET external data and combine it with my current view?

I have a view that I want to use to pull Model data + get data from an external API. Using the same URL path to get database data + external API data, as they are both relatively connected in terms of business logic.
This is how I tried implementing it:
class BucketList(generics.ListAPIView):
permission_classes = [IsAuthenticated]
serializer_class = BucketListSerializer
filter_backends = [OwnerOrUserFilterBackend]
queryset = Bucket.objects.all()
# I use a field in my model as part of my GET request
def get(self, request, *args, **kwargs):
bucket_symbols = Bucket.objects.only('stock_list')
symbols_unicode = (','.join(map(str, bucket_symbols)))
postgrest_urls = f"http://localhost:3000/rpc/bucketreturn?p_stocks=%7B{symbols_unicode}%7D"
response = requests.get(postgrest_urls, headers={'Content-Type': 'application/json'}).json()
return Response(response, status=status.HTTP_200_OK)
The idea of def get(), is to extract every stock_list field in objects, and feed that into my other API on localhost. To clarify, I want every stock_list in object passed into my get requests and returned, for each object.
However I keep getting undefined errors in my JSON response.
How can I properly implement a two-in-one view solution for my view, I still want to keep my original queryset = Bucket.objects.all() in my view.

How to process Ajax Data in Python (Django)

I want to push front end data (Form inputs) to the server via Ajax. For this, I created an Ajax post request but I'm very unsteady...
At my first attemps, I constantly receive errors by python
Ajax call:
//Get journey time for the stated address
jQuery.ajax({
type: 'post',
url: 'http://127.0.0.1:8000/termin/get-journey-time/',
data: {
'method': 'get_journey_time',
'mandant_id': 1,
'customer_address': customer_address,
'staff_group': staff_group_id
},
error: function (jqXHR, textStatus, errorThrown) {
console.log("Error")
},
timeout: 120000,
});
I've created a view in Python, in which I want to do something (views.py)
class get_journey_time(generics.ListAPIView):
"""
Handle Ajax Post to calculate the journey time to customer for the selected staff group
"""
permission_classes = (AllowAny,)
def post(self, request, *args, **kwargs):
print(request)
In my url route file I have this code lines (urls.py)
urlpatterns = [
XXXXXXXXXXXXXXXXXXXXXXXXX,
path('termin/get-journey-time/', views.get_journey_time.as_view()),
XXXXXXXXXXXXXXXXXXXXXXXXX,
XXXXXXXXXXXXXXXXXXXXXXXXX,
]
I got the Error code 500:
Expected a `Response`, `HttpResponse` or `HttpStreamingResponse` to be returned from the view, but received a `<class 'NoneType'>`
Is there a mistake in my approach, did I miss anything or is it completely crap?
Define renderer classes and parser classes in settings.py.
Note: You can define many of these (based on requirements and needs) but here we only need JSON related.
As a reference, you can check my repo's this file https://github.com/hygull/p-host/blob/master/src/pmt_hostel_app/views.py. I have used function based views, just ignore the code inside it and focus on request.data and also check related HTML files.
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': (
'rest_framework.parsers.JSONParser',
),
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
)
}
In this way you will be able to access the posted data in the form of dictionary which can be obtained using request.data in views.
Finally, return Response from the post() method. By default return type of function/method is None and you are just printing the request.
Check the below mentioned links, it will help you a lot.
https://www.django-rest-framework.org/api-guide/renderers/
https://www.django-rest-framework.org/api-guide/parsers/
In client code, I mean in JavaScript code, define a success callback as well (you have just defined error callback).
Please comment, if you are stuck.
you can do it like this
from rest_framework.response import Response
from rest_framework.views import APIView
class get_journey_time(APIView):
# ListAPIView is used for read-only endpoints
#
"""
Handle Ajax Post to calculate the journey time to customer for the selected staff group
"""
permission_classes = (AllowAny,)
def post(self, request, *args, **kwargs):
# you can get the posted data by request.data
posted_data = request.data
data = {"test": "test"}
return Response(data)
you can get the posted data and use serializers. you can start learning playing with serializers from here
Example serializer code can be like this
from rest_framework import serializers
class DummySerializer(serializers.Serializer):
name = serializers.CharField()
mobile_number = serializers.CharField(required=False)
and then use it in post method of your get_journey_time class

Categories