Home > OS >  How to check the data of related fields for compliance with the user before creating a record in dja
How to check the data of related fields for compliance with the user before creating a record in dja

Time:06-09

I recently started using django rest framework. I have an application in which the user model has a "company" field, so several users can be in the same company and work with common data. Each company can have one or more warehouses in which goods are stored (each company has its own) There is a page in which data is collected from forms in json and sent to the server via api

[
    {
        "id": 9,
        "doc_type": 1,
        "warehouse": 5,
        "date": "2022-06-07",
        "number": 98,
        "contragent": 3,
        "comment": "",
        "items": [
            {
                "product": 7,
                "buy_price": "1689.00",
                "sell_price": "2000.00",
                "quantity": 1
            }
        ]
    },

Problem: If the user somehow gets this api and changes the id for example of the "warehouse" field to the id of the warehouse of another company, then the document will be created anyway, also if the user replaces the id of the "product" field
Question: How can I check the data for compliance with the user's company before creating it?
Here is my code:

#models.py
Class CustomUser(AbstractUser):
    ...
    company = models.ForeignKey(Company, on_delete=models.PROTECT, null=True)
    ...

class Company(models.Model):
    name = models.CharField(max_length=50)
    ...

class Warehouse(models.Model):
    name = models.CharField(max_length=200)
    company = models.ForeignKey(Company, on_delete=models.CASCADE)


#serializers.py
class ConsignmentNoteSerializer(serializers.ModelSerializer):
    creator = serializers.HiddenField(default=serializers.CurrentUserDefault())
    items = ConsignmentItemSerializer(many=True)


    class Meta:
        model = ConsignmentNote
        fields = ['id', 'doc_type', "warehouse", 'date', 'number', 'contragent', 'comment', 'creator', 'items']
        read_only_fields = ['id' ]

#This is how I create the document
    def create(self, validated_data):
        items = validated_data.pop('items')
        note = ConsignmentNote.objects.create(**validated_data)
        for item in items:
            product = item.pop('product')
            item = ConsignmentItem.objects.create(consignmentnote=note, product=product ,**item)
        return note

I can't figure out where I should declare the create method. In serializers or in views?

#views.py
class ConsignmentNoteViewSet(viewsets.ModelViewSet):
    # queryset = ConsignmentNote.objects.all()
    serializer_class = ConsignmentNoteSerializer
    permission_classes = [permissions.IsAuthenticated]

    def get_queryset(self):
        user_company = self.request.user.company
        return ConsignmentNote.objects.filter(warehouse__company=user_company)

CodePudding user response:

To solve I usually will be creating a custom permission for this api-view. So to use something like

#views.py
class ConsignmentNoteViewSet(viewsets.ModelViewSet):
    # queryset = ConsignmentNote.objects.all()
    serializer_class = ConsignmentNoteSerializer
    permission_classes = [UserIsMemberOfCompany]

    def get_queryset(self):
     ...

To do that, I recommend, create a new file permissions.py inside same app folder. And create your permission class.

#permissions.py
class UserIsMemberOfCompany(permissions.BasePermission):
    def has_permission(self, request, view):
        # return True if request.user.id if is part of Company
        
        # to do that you could request the user
        request.user.id
        
        # request the id of Company by 'supposing that your passing the
        # id by somehow in path variable or query_params'.
        request.path_variable['company_id']
        
        # and check if the requested user is on this company
        # could be a filter or something like
        
        # return False in else

CodePudding user response:

Based on a response from Carlos-Carvalheira
This should work

class UserIsMemberOfCompany(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        if request.user.company.id == obj.warehouse.company.id:
            return True
        else:
            return False
  • Related