Как проверить данные связанных полей на соответствие пользователю перед созданием записи в django rest framework?
Добрый вечер, мне нужна помощь. Я недавно начал использовать django rest framework. У меня есть приложение, в котором в модели пользователя есть поле "компания", поэтому несколько пользователей могут быть в одной компании и работать с общими данными. У каждой компании может быть один или несколько складов, на которых хранятся товары (у каждой компании свой). Есть страница, на которой данные собираются из форм в json и отправляются на сервер через 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
}
]
},
Проблема: Если пользователь каким-то образом получит этот api и изменит id, например, поля "склад" на id склада другой компании, то документ все равно будет создан, также если пользователь заменит id поля "продукт"
.
Вопрос: Как я могу проверить данные на соответствие компании пользователя перед созданием документа?
Вот мой код
#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
Я не могу понять, где я должен объявить метод create. В сериализаторах или в представлениях?
#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)
Для решения проблемы я обычно создаю пользовательское разрешение для этого api-view. Таким образом, чтобы использовать что-то вроде
permissions = [UserIsMemberOfCompany]
Для этого я рекомендую создать новый файл permissions.py в той же папке app. И создайте свой класс разрешений.
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
Основано на ответе от Карлоса-Карвальейры
Это должно работать
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