I have to pass the product_id (which is a string) into a view. There I have to do some DB operations based on the product id. How can I get that product id in that view? Actually what should be the parameter in the class ProductDetailConfiguration view? Now I am passing viewsets.ModelViewSet. Actually, this API call is not completely related to any model.
# urls.py
url(r'^product-configuration/(?P<product_id>[\w-]+)/$', views.ProductDetailConfiguration, name='product-configuration'),
# views.py
class ProductDetailConfiguration(viewsets.ModelViewSet):
queryset = Product.objects.all()
def get_queryset(self, **kwargs):
queryset = Product.objects.all()
product_id = self.request.get('product_id', None)
#filter query set based on the product_id
return queryset
serializer_class = ProductConfigurationSerializer
The URL parameters are available in self.kwargs.
From the documentation:
Filtering against the URL
Another style of filtering might involve restricting the queryset based on some part of the URL.
For example if your URL config contained an entry like this:
url('^purchases/(?P<username>.+)/$', PurchaseList.as_view()),
You could then write a view that returned a purchase queryset filtered by the username portion of the URL:
class PurchaseList(generics.ListAPIView):
serializer_class = PurchaseSerializer
def get_queryset(self):
"""
This view should return a list of all the purchases for
the user as determined by the username portion of the URL.
"""
username = self.kwargs['username']
return Purchase.objects.filter(purchaser__username=username)
You have to use lookup_field in your views to get product_id and the view should not belongs to any model. Here I already answer a question like yours using django rest framework to return info by name
Hope this will help to solve your problem.
This is my approach:
Update URL:
url(r'^product-configuration$', views.ProductDetailConfiguration, name='product-configuration'),
In view.py:
class ProductDetailConfiguration(viewsets.ModelViewSet):
lookup_field = 'product_id'
serializer_class = ProductConfigurationSerializer
def retrieve(request, product_id=None, *args, **kwargs):
queryset = self.get_queryset()
# Filter with produc_id
# print(product_id)
# Return Response
You can get the data from the request url by :-
data_dict = self.request.data
This will return a dictionary of all the parameters of the request url.
You can use the parameter name as the key
Related
Demo model
class Item(models.Model):
name = models.CharField(max_length=20)
Demo view
class ItemViewSet(viewset.ModelViewSet):
queryset = Item.objects.all()
serializer_class = ItemSerializer
Demo input passing using API post request
[ {name: 'Book'}, {name: 'PC'}, {name: 'Phone'} ]
How to create multiple table records with single post request?
This is how I used to do with Flask, I went through Django documentation and tried to override the create method.
class ItemViewSet(viewset.ModelViewSet):
queryset = Item.objects.all()
serializer_class = ItemSerializer
def create(self, request, *args, **kwargs):
data = request.data
for item in data:
record = Item(name=item.name)
record.save()
return Response(status=200)
Iam using a generic ListApiView of Django Restframework, the serializer iam using consist of many other serializer(nested serializers). I need to know how I can use the keyword from URL and pass it to the serializer in order for me to filter the result using the keyword in the URL.
For example I have a api view as this
class GetList(Generics.ListApiView):
serializer Class = ABCSerializer
I want to pass a value from a URL, to filter some parts of results produced by the serializer. This ABCSerializer is composed of many other nested serializers. I want to filter the result using the Value from URL not like primary key.
In the below example it shows the filter based on username in the URL.
url('^purchases/(?P<username>.+)/$', PurchaseList.as_view()),
we can write a view that returned a purchase queryset filtered by the username portion of the URL:
class PurchaseList(generics.ListAPIView):
serializer_class = PurchaseSerializer
def get_queryset(self):
"""
This view should return a list of all the purchases for
the user as determined by the username portion of the URL.
"""
username = self.kwargs['username']
return Purchase.objects.filter(purchaser__username=username)
using the same approach as the above, I want to use a filter a query based on a string that is other than username, and also pass this string to the serializer. and use it as filter in nested serializers.
Thanks
You could use DjangoFilterBackend for filtering on your model's fields.
You can do it by following steps
Install Django Filter into your Django application.
pip install django-filter
Add default filter backend to your settings.py
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}
Enter filter_backends property of your view/ viewset that you want filter to be applied.
from django_filters.rest_framework import DjangoFilterBackend
class PurchaseList(generics.ListAPIView):
...
filter_backends = (DjangoFilterBackend,)
Add list of fields on model to filterset_fields property on your view/ viewset for applying filters to those fields.
class PurchaseList(generics.ListAPIView):
queryset = Purchase.objects.all()
serializer_class = PurchaseSerializer
filter_backends = (DjangoFilterBackend,)
filterset_fields = ('category', 'other_field')
I hope this would help you to filter on ListAPIViews.
For more details visit API Guide on Django filter
For advanced filter use/ visit package django-rest-framework-filters
I have the following setup:
I want to list all holidays of a specific year. That's why I leave out the default list view and implement my own like this:
class HolidayViewSet(mixins.RetrieveModelMixin, GenericViewSet):
#list_route()
def year(self, request, year=get_today().year):
public_holidays = self.get_queryset().filter(date__year=year)
page = self.paginate_queryset(public_holidays)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(public_holidays, many=True)
return Response(serializer.data)
If I use the default /holiday/year/ I get a result for the current year.
But whe I try to pass a parameter, I'll get a 404. The 404 page (in debug mode) even shows me the correct URL pattern:
api/v1/ ^holiday/year/$ [name='holiday-year']
api/v1/ ^holiday/year\.(?P<format>[a-z0-9]+)/?$ [name='holiday-year']
In the documentation this aspect is unfortunately not covered.
Any ideas why my route to holiday/year/2017 is not working?
Ok, my workaround is using django-filter.
My filter:
class HolidayFilter(filters.FilterSet):
"""
This filter can be used to filter holidays by different values in API views or viewsets.
See http://django-filter.readthedocs.io/en/1.1.0/guide/rest_framework.html
"""
year = filters.NumberFilter(name='date', lookup_expr='year')
class Meta:
model = Holiday
fields = ['date']
My viewset:
class HolidayListViewSet(ModelViewSet):
def list(self, request, *args, **kwargs):
# Apply filters
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
# Pagination
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
# Serializer
serializer = self.get_serializer(queryset, many=True)
# Response
return Response(serializer.data)
The URL:
/api/v1/holiday/?year=2016
DRF differentiates list and detail requests. list request is not expected to have additional path parameter(i.e. /{id}), while detail request, in opposite, defined by it.
What it means is #list_route decorator creates /holiday/year endpoint, and #detail_route will create /holiday/{id}/year endpoint.
I think my approach is so simple but its useful. just determine your Router like below:
urlpatterns += [
path(r'holiday/<int:year>/', TestListView.as_view()),
]
The URL:
api/v1/holiday/2016/
Then create your view like this:
class TestListView(generics.ListAPIView):
serializer_class = TestSerializer
def get(self, request, *args, **kwargs):
year = kwargs.get('year', '')
query_set = Test.objects.filter(year__exact=year) # Test is my test model
serializer = self.get_serializer(query_set, many=True)
return Response(serializer.data)
I have a Product model and one propery in it is "my_test_fn". This is called from my serializer. My requirement is, I want to do some calculations based on the filter passing through the url. How can I get the url parameter values in a model property?
I want to get "filters" value in my_test_fn
models.py
class Product(AbstractProduct):
product_id = models.UUIDField(default=uuid.uuid4, editable=False)
##more fields to go
def my_test_fn(self):
filters = self.request.query_params.get('filters', None)
return {"key":"value"}
serializer.py
class MySerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = ('id','product_id','sku', 'title', 'my_test_fn',)
views.py
class ProductDetailConfiguration(viewsets.ViewSet):
lookup_field = 'product_id'
def retrieve(self, request, product_id=None):
queryset = Product.objects.filter(product_id=product_id)[0]
serializer = ProductConfigurationCustomSerializer(queryset, context={'request': request})
return Response(serializer.data)
API url:
http://127.0.0.1:8000/api/v1/product-configuration/2FC2AA43-07F5-DCF4-9A74-C840FDD8280A?filters=5
This logic belongs in the serializer, not the model. You can access it there via self.context['request'].
I guess what you want is not possible (have the my_fn on the model itself).
You would need to use a SerializerMethodField, so you will have access to the object, but to the request (and the various parameters of it) as well.
I'm using Django Rest Framework and python-requests and passing several variables through the URL as shown below.
GET /api/boxobjects/?format=json&make=Prusa&model=i3&plastic=PLA HTTP/1.1
I'm passing the variables make, model, and plastic. The recommended method to access these parameters is shown below.
makedata = request.GET.get('make', '')
However, I have no idea where to place that line of code. I've completed the tutorial for Django Rest Framework and have my views set up to roughly match the tutorial.
views.py:
#api_view(['GET'])
#login_required
def api_root(request, format=None):
return Response({
'Users': reverse('api:user-list', request=request, format=format),
'Objects': reverse('api:object-list', request=request, format=format),
'Files': reverse('api:file-list', request=request, format=format),
'Config Files': reverse('api:config-list', request=request, format=format),
'Box-objects': reverse('api:box-object-list', request=request, format=format),
})
class BoxViewSet(viewsets.ModelViewSet):
queryset = Uploadobject.objects.all().exclude(verified=False)
serializer_class = BoxSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,
IsBox)
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
#Maybe get function here? Not displaying
'''
def get(self, request):
print ("request set here?")
'''
Where would I place the one line of code to access these request parameters?
class BoxViewSet(viewsets.ModelViewSet):
queryset = Uploadobject.objects.all().exclude(verified=False)
serializer_class = BoxSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,
IsBox)
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
def get_queryset(self):
req = self.request
print(req)
make = req.query_params.get('make')
if make:
self.queryset = uploadobject.objects.filter(make=make)
return self.queryset
else:
return self.queryset
What is the statement doing ?
If 'make' is in the query params of the request then overwrite the BoxViewSet queryset property with a new queryset based on 'make' and return it. otherwise return the default queryset that excludes any objects that isn't verified.
Based on Django Rest Framework's Filtering Documentation, there are two ways to access parameters from a request.
1. URL Params
If you are using URL params (such as mywebapp.com/api/<user_slug>/resource/), you can access the arguments like this: self.kwargs['param_name'] where param_name is the name of the parameter you're trying to get the value for. So for the example above, you'd have user_slug = self.kwargs['user_slug']
Example from the documentation
If your URL structure looks like this:
url('^purchases/(?P<username>.+)/$', PurchaseList.as_view()),
...and want to filter on that username. You can override the get_queryset() and your view will look like this:
class PurchaseList(generics.ListAPIView):
serializer_class = PurchaseSerializer
def get_queryset(self):
"""
This view should return a list of all the purchases for
the user as determined by the username portion of the URL.
"""
username = self.kwargs['username']
return Purchase.objects.filter(purchaser__username=username)
2. Query Params
If you are using query parameters such as mywebapp.com/api/resource?user_slug=plain-jane, you can use self.request to access request as you can in plain vanilla Django REST methods. This gives you access to things like self.request.query_params. For the example above, you would say user_slug = self.request.query_params['user_slug']. You can also access the current user like user = self.request.user.
Example from the documentation
Let's say you want to support a request structure like this:
http://example.com/api/purchases?username=denvercoder9
...and want to filter on that username. Do this to override the queryset:
class PurchaseList(generics.ListAPIView):
serializer_class = PurchaseSerializer
def get_queryset(self):
"""
Optionally restricts the returned purchases to a given user,
by filtering against a `username` query parameter in the URL.
"""
queryset = Purchase.objects.all()
username = self.request.query_params.get('username', None)
if username is not None:
queryset = queryset.filter(purchaser__username=username)
return queryset
Django 2
Use request.parser_context
def perform_create(self, serializer):
post_id = self.request.parser_context['kwargs'].get('post_id')
post = Post.objects.get(id=post_id)
serializer.save(post=post)
adding a little to what they have already contributed, for the POST methods in modelviewset when an object is sent, it is necessary to use request.data['myvariable']
example:
class BoxViewSet(viewsets.ModelViewSet):
queryset = Uploadobject.objects.all().exclude(verified=False)
serializer_class = BoxSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,
IsBox)
def create(self, request):
...
make = request.data['make']