djangourlroutesdjango-rest-framework

Django RestFramework make lookup_field accept special characters (".")


I am working on a DRF viewset which has a custom query (using annotate to group data), for this I want to implement list, retrive and delete functions based on a field called "batch" which contains a string with special characters like "-" and ".". I am able to make the viewset to list and retrive data but the data retrival fails when special characters (".") are present in the batch string. How can I setup viewset router to allow "." in the batch name?

class BatchViewSet(viewsets.ModelViewSet):
    queryset = Product.objects.values('batch', 'customer', 'order_number').annotate(
        total_quantity=Sum('total_quantity'),
        ready_quantity=Sum('ready_quantity')
    ).filter(deleted_at__isnull=True).all()
    serializer_class = BatchSerializer

    lookup_field = 'batch'

    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    search_fields = ['batch', 'customer', 'order_number']

    ordering_fields = ['batch', 'customer', 'order_number',
                       'total_quantity', 'ready_quantity']
    ordering = ['batch']

    def create(self, request, *args, **kwargs):
        raise MethodNotAllowed('POST')

router.register(r'batches', BatchViewSet, basename="batches")

These are the routes generated to get the batch details

products/ ^batches/(?P<batch>[^/.]+)/$ [name='batches-detail']
products/ ^batches/(?P<batch>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='batches-detail']

which is not working on my batch TEATECH.01427964.11.08 but working on TEATECH.

I tried making a custom router to get the batch number but it is also not working and I can't create a regex which can process the batch. Similarly I can't setup lookup_field_regex to catch the batch string.

I can navigate my batch retrival by using the batch name inside the search products/batches?search=TEATECH.01427964.11.08 like this, but it is a hacky solution and will not work with delete batch function, so how should I handle it?


Solution

  • Added re_path in the path of viewsets to receive characters such as TEATECH.01427964.11.08.

    urls.py

    from rest_framework.routers import DefaultRouter
    from django.urls import re_path
    from . import views
    
    
    router = DefaultRouter()
    batch_detail = views.BeeViewSet.as_view(
        {"get": "retrieve", "patch": "partial_update", "delete": "destroy"})
    router.register(r"batches", BatchViewSet, basename="batches")
    
    urlpatterns = [
      re_path(r"^products/batches/(?P<batch>[^/*]+)/$", batch_detail),
    ]
    
    urlpatterns += router.urls
    

    When you add the above route, the below request works.

    GET --> products/batches/TEATECH.01427964.11.08/

    The questioner asked for a query string form(products/batches?search=TEATECH.01427964.11.08), but '?' does not work as intended in django's re_path.

    Maybe it's because it overlaps with the querystring, but it's not accurate.(If anyone knows anything about this, please comment)

    It's awkward to remove only '?'(products/batches/search=TEATECH.01427964.11.08), so I made it in the basic formet provided by viewsets.

    It's a lack answer, but I thought it could help as an alternative, so I answerd.