Django 1.11.15 and query string parameters - django-rest-framework

I am trying to query from django i.e http://localhost:8000/search/Tesco/apples to get a query of json list, the one below.
[
{
"id": 12,
"Date": "2018-08-02",
"Title": "Rosedene Farms Small Sweet Apple 520G",
"Price": 0.96,
"PricePerWeight": "1.85/kg",
"FinalOffer": "undefined undefined",
"ProductID": 292249576
},
My urls.py:
from django.conf.urls import url, include
from . import views
from rest_framework import routers
router = routers.DefaultRouter()
router.register('Tesco', views.TescoView)
urlpatterns = [
url('', include(router.urls), name='search'),
url(r'^search/', include(router.urls), name='searchTwo')
my views.py
from __future__ import unicode_literals
from django.shortcuts import render
from rest_framework import viewsets
from .models import Tesco
from .serializers import TescoSerializers
from django.core.urlresolvers import reverse_lazy, reverse
class TescoView(viewsets.ModelViewSet):
queryset = Tesco.objects.filter(Title__icontains='apple')
serializer_class = TescoSerializers
how would I get the URL http://localhost:8000/search/tesco/ to query through the database for the list of json?

I don't think searching like:
http://localhost:8000/search/Tesco/apples
is a normal pattern in Django Rest Framework (DRF), so I think you're going to hit a lot of resistance trying to make this pattern work with DRF. If I may suggest, I believe you're in the X-Y Problem space - "That is, you are trying to solve problem X, and you think solution Y would work, but instead of asking about X when you run into trouble, you ask about Y."
Normally, filtering parameters are specified on the listing view of the model. For your model, your complete Tesco instance listing can be found at:
http://localhost:8000/Tesco/
If you want to filter this down, you append query parameters after a ? like:
http://localhost:8000/Tesco/?title__icontains=apple
or
http://localhost:8000/Tesco/?ProductID=292249576
or multiple searching filters like:
http://localhost:8000/Tesco/?ProductID=292249576&title__icontains=apple
To use this pattern, you need to modify your viewset and add a FilterSet. This is what your views.py file would look like:
from __future__ import unicode_literals
from django.shortcuts import render
from rest_framework import viewsets
from .models import Tesco
from .serializers import TescoSerializers
from django.core.urlresolvers import reverse_lazy, reverse
# Import filtering libraries
import django_filters
from rest_framework import filters
class TescoFilterSet(django_filter.FilterSet):
title__icontains = django_filter.Filter('Title', lookup_expr='icontains')
class Meta:
model = Tesco
fields = ('title__icontains', 'ProductID')
class TescoView(viewsets.ModelViewSet):
queryset = Tesco.objects.filter(Title__icontains='apple')
serializer_class = TescoSerializers
# Hook up filterset
filter_backends = (django_filters.rest_framework.DjangoFilterBackend, filters.OrderingFilter,)
filter_class = TescoFilterSet
# allow ordering on any field
ordering_fields = '__all__'
In my experience the nginx and apache webservers seem to work well with this pattern when you get to content caching.
For more on filtering, see the DRF guide on Filtering.
Ordering
Per your comment, you can order by specifying order_fields as seen above. Then you can add the ordering parameter.
vvvvvvvvvvvvvv
http://localhost:8000/Tesco/?title__icontains=apple&ordering=price
This will be ascending price.
Add a - before price and the order is reversed or descending:
http://localhost:8000/Tesco/?title__icontains=apple&ordering=-price
^

Related

How do I filtered a generic object from model ,store it like Radis and Return a unique string(key) against this object using django

I'm beginner in Django.I get stuck from last 3 days by doing this task.I have try on google, Youtube but unfortunately failed to complete.Actually, I want to design a Api in which I filter data against title from jobs model that is in working.but the problem is that I want to first filter data from jobs model then store it against a unique id(string that is xyz) in storage, storage could be any like Redis or database and also return the same string(xyz) in response Api.Id will be use later on for result Api.
Please, help me I shall be very thankful to you
#My Jobs view
View.py
from rest_framework import viewsets, mixins
from .models import Job
from .serializers import JobSerializer
from rest_framework import filters,fields, serializers
from rest_framework import filters
class JobViewSet(
mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.ListModelMixin,
viewsets.GenericViewSet,
):
"""
Updates and retrieves user accounts
"""
queryset = Job.objects.all()I want
serializer_class = JobSerializer
filter_backends = [filters.SearchFilter]
search_fields = ['title']

Using FileField/ImageField with Swagger UI and drf-spectacular

I have a Django REST Framework project which uses a ModelViewSet to create APIs for a model containing a FileField.
I've shared a full example of a Django project demonstrating this issue here. But to summarise the key components:
models.py
from django.db import models
class Profile(models.Model):
image = models.FileField(upload_to='uploads/%Y/%m/%d/')
views.py
from rest_framework import (
viewsets,
serializers,
parsers,
)
from sample import models
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = models.Profile
fields = ['id', 'image']
read_only_fields = ['id']
class ProfileViewSet(viewsets.ModelViewSet):
serializer_class = ProfileSerializer
queryset = models.Profile.objects.all()
urls.py
from drf_spectacular.views import (
SpectacularAPIView,
SpectacularSwaggerView,
)
from django.contrib import admin
from django.urls import path, include
from django.conf.urls.static import static
from django.conf import settings
from rest_framework.routers import DefaultRouter
from sample import views
router = DefaultRouter()
router.register('profile', views.ProfileViewSet)
urlpatterns = [
path('admin/', admin.site.urls),
path('api/schema/', SpectacularAPIView.as_view(), name='api-schema'),
path(
'api/docs/',
SpectacularSwaggerView.as_view(url_name='api-schema'),
name='api-docs',
),
path('', include(router.urls)),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
settings.py (REST_FRAMEWORK configuration only):
REST_FRAMEWORK = {
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
}
requirements.txt
Django==3.2.3
djangorestframework==3.12.4
drf-spectacular==0.16.0
I am generating browsable Swagger-UI docs using drf-spectacular to document the API.
The problem is that the FileField input in Swagger-UI is a string input, and doesn't give the option to set a file:
I would like to have a file input where I can choose a file which will be sent to the API.
My question is: How can I configure DRF or drf-spectacular to show this field?
After some digging through the drf-spectacular docs and GitHub issues, I found that the FileField can be set to binary by adding the following to in settings.py:
SPECTACULAR_SETTINGS = {
'COMPONENT_SPLIT_REQUEST': True
}
Also in Swagger UI, make sure you change the content-type from application/json to multipart/form-data and click Try it out. The upload button will apppear.

Rename field in Serializer.data

I am currently implementing an API client for which I want to validate the request sent using serializers.
To do so, I create my serializer like this:
class TransactionRequestSerializer(serializers.Serializer):
counterparty = serializers.UUIDField(required=False)
from_datetime = serializers.DateTimeField(required=False, source='from')
to_datetime = serializers.DateTimeField(required=False, source='to')
transaction_type = serializers.CharField(required=False, source='type')
Issue is that source doesn't fit my usage, because when I do serializer.data, I get:
{'from_datetime': '2020-07-07T16:08:00.313236+02:00'}
Instead of
{'from': '2020-07-07T16:08:00.313236+02:00'}
Those data are then passed as params for my request, like requests.get('', params=params)
Of course, I cannot name the field "from" as it is reserved. Any idea about how can I get "from" in my serializer.data?
I tink this has already been answered.
Please take a look at this question: How to change field name in Django REST Framework
I think the same solution will work for you.
I think it's not possible, so I switched to Serializer.validated_data instead so I can use source.
this example as same the question :
model:
from django.db import models
class ReceiveCallbackUrl(models.Model):
From = models.CharField(max_length=14)
to = models.CharField(max_length=14)
message = models.CharField(max_length=255)
messageid = models.IntegerField()
serializer:
from rest_framework.serializers import ModelSerializer,SerializerMethodField
from .models import ReceiveCallbackUrl
class ReceiveCallbackUrlModelSerializer(ModelSerializer):
From = SerializerMethodField('from')
class Meta:
model = ReceiveCallbackUrl
fields = ['From', 'to', 'message', 'messageid']
view:
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .serializer import ReceiveCallbackUrlModelSerializer
class ReceiveCallbackUrlAPIView(APIView):
def post(self, request):
serializer = ReceiveCallbackUrlModelSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(request.POST, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_406_NOT_ACCEPTABLE)

DRF - in filter, use field-value instead of default pk / id

I'm trying to use DRF's filters so that the URL query is like so:
/roadname/?road=M5
not like so
/roadinfo/?road=1
I can't seem to do it when I've got a ForeignKey relationship.
I've tried using lookup_field with no luck (although not sure how this would work for multiple filter fields anyway - I don't think that's the answer). I've tried using a get_queryset() method in views as in the second example in the documentation. A comment I came across suggested that this is bad RESTApi practice - is it? How would a user know to type in '1' to get results for 'M5' in a front-end client?
I've set up two really simple models (and serializers, views, etc.) to try these out as below.
If I use RoadName, I have to type the name into the filter search box (rather than having a dropdown), but the url query is how I want it.
If I use RoadInfo (which has a ForeignField to RoadName), I get a drop down in the filter box, but the url query uses the ForeignKey pk.
My question: How can I set it so that when I use RoadInfo, the query uses the field value rather than the id/pk?
Models
from django.db import models
class RoadName(models.Model):
road = models.CharField(max_length=50)
def __str__(self):
return str(self.road)
class RoadInfo(models.Model):
road = models.ForeignKey(RoadName, on_delete='CASCADE')
# other data
def __str__(self):
return str(self.road)
Serializers
from traffic.models import *
from rest_framework import serializers
class RoadNameSerializer(serializers.ModelSerializer):
road = serializers.CharField()
class Meta:
model = RoadName
exclude = ('id',)
class RoadInfoSerializer(serializers.ModelSerializer):
road = RoadNameSerializer()
class Meta:
model = RoadInfo
exclude = ('id',)
Views
from traffic.serializers import *
from traffic.models import *
from django_filters import rest_framework as filters
from rest_framework import viewsets
class RoadNameViewSet(viewsets.ReadOnlyModelViewSet):
""" List of all traffic count Counts """
queryset = RoadName.objects.all()
serializer_class = RoadNameSerializer
filter_backends = (filters.DjangoFilterBackend,)
filterset_fields = '__all__'
class RoadInfoViewSet(viewsets.ReadOnlyModelViewSet):
""" List of all traffic count Counts """
queryset = RoadInfo.objects.all()
serializer_class = RoadInfoSerializer
filter_backends = (filters.DjangoFilterBackend,)
filterset_fields = '__all__'
The data M5 on the road attribute of RoadName model. It can be filtered by road__road from RoadInfo model.
So, Try /roadname/?road__road=M5

restframework-jwt how can I handle payload?

I used Django restframework to implement api server.
Also I used djangorestframework-jwt for token authentication.
[urls.py]
from django.contrib import admin
from django.urls import path, include
from rest_framework_jwt.views import refresh_jwt_token
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('rest_auth.urls')),
path('registration/', include('rest_auth.registration.urls')),
path('refresh-token/', refresh_jwt_token),
]
Everything works fine. But I want to know that How can I extract payload from token?
For example, There is article table.
[/article/serializers.py]
from rest_framework import serializers
from . import models
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = models.Article
fields = '__all__'
[models.py]
from django.db import models
class Article(models.Model):
subject = models.CharField(max_length=20)
content = models.CharField(max_length=100)
[views.py]
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from . import models, serializers
class Article(APIView):
def get(self, request, format=None):
all_article = models.Article.objects.all()
serializer = serializers.ArticleSerializer(all_article, many=True)
return Response(data=serializer.data, status=status.HTTP_200_OK)
In this case, I want to return correct response only payload['userid'] == article's userid.
How can I extract username from jwt token?
Previous, I just use jwt not djangorestframework-jwt, So just decode request data and use it.
But now I use djangorestframework-jwt, I confused How can I do it.
Is there any solution about this?
Thanks.
I solved this issue after checking the library's documentation here
https://jpadilla.github.io/django-rest-framework-jwt/
I needed to Override all the functions to return custom response as required in my application.
Also any additional settings we need to specify in JWT_AUTH in settings.py of my application.
i.e.
JWT_AUTH = {
'JWT_RESPONSE_PAYLOAD_HANDLER':
'myapp.utils.jwt_response_payload_handler',
}
And needed to define jwt_response_payload_handler function in a util folder in my app to override the default function.

Resources