Kim Stacks
Kim Stacks

Reputation: 10822

How to refactor duplicate method inside class based views for Django 1.9

I have a class based view called PalletContentProductionView

@method_decorator(PermissionManager.production_worker_required, name='dispatch')
class PalletContentProductionView(APIView):
    """
    Update a Pallet Content count and/or product
    """
    def put(self, request, pk):
        pallet_content = QuickFind.get_pallet_content_or_404(pallet_content_id=pk)

        def validate_pending_and_created_by_user(pallet_content, user=request.user):
            if not pallet_content.pending():
                raise PermissionDenied("Non-Pending pallet content cannot be updated by production worker")
            EntryFormHelper.throw_403_when_not_created_by_user(pallet_content=pallet_content, user=user)
        return update_pallet_content(request, pallet_content, validate_pending_and_created_by_user)

    """
    Delete pallet only if pallet content is pending and creater by user
    """
    def delete(self, request, pk):
        pallet_content = QuickFind.get_pallet_content_or_404(pallet_content_id=pk)

        def validate_pending_and_created_by_user(pallet_content, user=request.user):
            if pallet_content.pending() is False:
                raise PermissionDenied("Non-Pending pallet content cannot be updated by production worker")
            EntryFormHelper.throw_403_when_not_created_by_user(pallet_content=pallet_content, user=user)
        return delete_pallet_content(request, pallet_content, validate_pending_and_created_by_user)

I was wondering how do I refactor such that the four lines of duplication can be avoided?

The four lines are :

def validate_pending_and_created_by_user(pallet_content, user=request.user):
        if not pallet_content.pending():
            raise PermissionDenied("Non-Pending pallet content cannot be updated by production worker")
        EntryFormHelper.throw_403_when_not_created_by_user(pallet_content=pallet_content, user=user)

I have tried to pull it out and make it inside the PalletContentProductionView and adjacent to the put and delete methods but it was wrong.

Upvotes: 0

Views: 239

Answers (1)

Régis B.
Régis B.

Reputation: 10618

Just create a method that generates the corresponding function:

@method_decorator(PermissionManager.production_worker_required, name='dispatch')
class PalletContentProductionView(APIView):
    def put(self, request, pk):
        pallet_content = self.get_pallet_content(pk)
        return update_pallet_content(
            request, pallet_content,
            self.generate_callback(request, pk)
        )

    def delete(self, request, pk):
        pallet_content = self.get_pallet_content(pk)
        return delete_pallet_content(
            request, pallet_content,
            self.generate_callback(request, pk)
        )

    def get_pallet_content(self, pallet_content_pk):
        return QuickFind.get_pallet_content_or_404(pallet_content_id=pk)

    def generate_callback(self, request, pallet_content):
        def validate_pending_and_created_by_user(pallet_content, user=request.user):
            if not pallet_content.pending():
                raise PermissionDenied("Non-Pending pallet content cannot be updated by production worker")
            EntryFormHelper.throw_403_when_not_created_by_user(pallet_content=pallet_content, user=user)
        return validate_pending_and_created_by_user

Note that here we also use a get_pallet_content to avoid the duplication of QuickFind.get_pallet_content_or_404(pallet_content_id=pk).

Also, note that you should use if not something: instead of if something is False:.

Upvotes: 1

Related Questions