Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django swagger- How to disable DjangoFilterBackend query filters from delete, put methods?

I've created an AssetsFilter class:

from django_filters import Filter
from django_filters import rest_framework as filters
from django_filters.fields import Lookup

from .models import Assets


class MyListFilter(Filter):
    def filter(self, qs, value):
        value_list = value.split(',')
        return super(ListFilter, self).filter(qs, Lookup(value_list, 'in'))


class AssetsFilter(filters.FilterSet):
    name = filters.CharFilter(lookup_expr='icontains', help_text=u'Filter by name')
    criticality = MyListFilter(name='critical', help_text=u'Filter by_id')

    class Meta:
        model = Assets
        fields = ['name', 'criticality ']

Now I'm using this filter in my Viewset as follows:

from .serializers import AssetSerializers
from .filters import AssetsFilter


class AssetViewSet(viewsets.ModelViewSet):
    """
    This viewset automatically provides `list`, `create`, `retrieve`,
    `update` and `destroy` actions.
    """
    queryset = Assets.objects.all()
    serializer_class = AssetSerializers
    filter_backends = (DjangoFilterBackend,)
    filter_class = AssetsFilter
    http_method_names = ['get', 'post', 'put', 'delete']

    def list(self, request):
        """
        Returns a list of Asset.
        """
        return super(AssetViewSet, self).list(request)

    def create(self, request):
        """
        Creates a new Asset.<br>
        """
        return super(AssetViewSet, self).create(request)

    def destroy(self, request, pk=None):
        """
        Deletes a Asset.
        """
        return super(AssetViewSet, self).destroy(request, pk=pk)

    def retrieve(self, request, pk=None):
        """
        Returns a Asset with id={id}
        """
        return super(AssetViewSet, self).retrieve(request, pk=pk)

    def update(self, request, pk=None, *args, **kwargs):
        """
        Updates an existing Asset.<br>
        """
        return super(AssetViewSet, self).update(request, pk=pk, *args, **kwargs)

When the swagger documentation is created, the filter fields appear in GET (list), GET (retrieve) as expected, but they also appear in the POST, PUT, PATCH and DELETE where they shouldn't be.

How can I disable those parameters from appearing in the latest version of django-rest-swagger and DRF?

like image 475
Ranvijay Sachan Avatar asked Dec 28 '17 12:12

Ranvijay Sachan


People also ask

What is the purpose of filter () method in Django?

The filter() method is used to filter you search, and allows you to return only the rows that matches the search term.

What is Query_params in Django?

query_params is a more correctly named synonym for request. GET . For clarity inside your code, we recommend using request. query_params instead of the Django's standard request.

What is Queryset in Django REST framework?

queryset - The queryset used for model instance lookups when validating the field input. Relationships must either set a queryset explicitly, or set read_only=True . many - If applied to a to-many relationship, you should set this argument to True .

How do I filter Queryset in Django REST framework?

The simplest way to filter the queryset of any view that subclasses GenericAPIView is to override the . get_queryset() method. Overriding this method allows you to customize the queryset returned by the view in a number of different ways.


2 Answers

If you don't want to Add Schema Manually(Every time) then Here is the solution: auto_schema.py

from rest_framework.schemas import AutoSchema
from django.utils.six.moves.urllib import parse as urlparse
import coreapi, coreschema


class CustomSchema(AutoSchema):
    def get_link(self, path, method, base_url):
        fields = self.get_path_fields(path, method)
        fields += self.get_serializer_fields(path, method)
        fields += self.get_pagination_fields(path, method)
        if self.view.action in ['list']:
            fields += self.get_filter_fields(path, method)

        manual_fields = self.get_manual_fields(path, method)
        fields = self.update_fields(fields, manual_fields)

        if fields and any([field.location in ('form', 'body') for field in fields]):
            encoding = self.get_encoding(path, method)
        else:
            encoding = None

        description = self.get_description(path, method)

        if base_url and path.startswith('/'):
            path = path[1:]

        return coreapi.Link(
            url=urlparse.urljoin(base_url, path),
            action=method.lower(),
            encoding=encoding,
            fields=fields,
            description=description
        )

views.py

class MyUserViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows users to be viewed or edited.

    """
    model = MyUser
    serializer_class = MyUserSerializer
    queryset = MyUser.objects.all()
    filter_backends = (DjangoFilterBackend, OrderingFilter)
    filter_class = MyUserFilter
    ordering_fields = ('last_name', 'first_name', 'email', 'is_active')
    ordering = ('last_name', 'first_name')
    permission_classes = (IsAuthenticated,)
    schema = CustomSchema()
like image 69
Ranvijay Sachan Avatar answered Oct 26 '22 23:10

Ranvijay Sachan


Specifying a CustomSchema for every model is not necessary. It is possible to override the DjangoFilterBackend and prevent it from adding the schema fields for some specified actions:

class MyDjangoFilterBackend(DjangoFilterBackend):
    def get_schema_fields(self, view):
        # Customize according to your need here.
        if view.action not in ["list"]:
            return []
        return super().get_schema_fields(view)

in settings.py :

REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': (
       'api.filter_backends.MyDjangoFilterBackend'
    ),
    'DEFAULT_PAGINATION_CLASS': 'api.pagination.MyPagination',
    'PAGE_SIZE': 20
} 
like image 44
Yohan D Avatar answered Oct 27 '22 01:10

Yohan D