Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

This QueryDict instance is immutable

Tags:

I have a Branch model with a foreign key to account (the owner of the branch):

class Branch(SafeDeleteModel):     _safedelete_policy = SOFT_DELETE_CASCADE     name = models.CharField(max_length=100)     account = models.ForeignKey(Account, null=True, on_delete=models.CASCADE)     location = models.TextField()     phone = models.CharField(max_length=20, blank=True,                          null=True, default=None)     create_at = models.DateTimeField(auto_now_add=True, null=True)     update_at = models.DateTimeField(auto_now=True, null=True)      def __str__(self):         return self.name      class Meta:         unique_together = (('name','account'),)      ... 

I have a Account model with a foreign key to user (one to one field):

class Account(models.Model):     _safedelete_policy = SOFT_DELETE_CASCADE     name = models.CharField(max_length=100)     user = models.OneToOneField(User)     create_at = models.DateTimeField(auto_now_add=True)     update_at = models.DateTimeField(auto_now=True)      def __str__(self):         return self.name + ' - ' + self.create_at.strftime('%Y-%m-%d %H:%M:%S') 

I've created a ModelViewSet for Branch which shows the branch owned by the logged in user:

class BranchViewSet(viewsets.ModelViewSet):     serializer_class = BranchSerializer     permission_classes = (permissions.IsAuthenticated,)       def get_queryset(self):         queryset = Branch.objects.all().filter(account=self.request.user.account)         return queryset 

Now to create a new branch, I want to save account field with request.user.account, not with data sent from the rest client (for more security). for example:

def create(self, request, *args, **kwargs):     if request.user.user_type == User.ADMIN:         request.data['account'] = request.user.account         return super(BranchViewSet, self).create(request, *args, **kwargs)  def perform_create(self, serializer):     '''         Associate branch with account     '''     serializer.save(account=self.request.user.account) 

In branch serializer

class BranchSerializer(serializers.ModelSerializer):     account = serializers.CharField(source='account.id', read_only=True)      class Meta:         model = Branch         fields = ('id', 'name', 'branch_alias',               'location', 'phone', 'account')         validators = [             UniqueTogetherValidator(                 queryset=Branch.objects.all(),                 fields=('name', 'account')             )         ] 

but I got this error: This QueryDict instance is immutable. (means request.data is a immutable QueryDict and can't be changed)

Do you know any better way to add additional fields when creating an object with django rest framework?

like image 521
Rowegie Lambojon Avatar asked Jun 23 '17 09:06

Rowegie Lambojon


People also ask

Is Django Queryset immutable?

The QuerySet is immutable - chaining methods to our queryset doesn't modify the original queryset - it creates a new one.

What is QueryDict Django?

class QueryDict. In an HttpRequest object, the GET and POST attributes are instances of django.http.QueryDict , a dictionary-like class customized to deal with multiple values for the same key. This is necessary because some HTML form elements, notably <select multiple> , pass multiple values for the same key.


1 Answers

As you can see in the Django documentation:

The QueryDicts at request.POST and request.GET will be immutable when accessed in a normal request/response cycle.

so you can use the recommendation from the same documentation:

To get a mutable version you need to use QueryDict.copy()

or ... use a little trick, for example, if you need to keep a reference to an object for some reason or leave the object the same:

# remember old state _mutable = data._mutable  # set to mutable data._mutable = True  # сhange the values you want data['param_name'] = 'new value'  # set mutable flag back data._mutable = _mutable 

where data it is your QueryDicts

like image 50
Максим Шатов Avatar answered Oct 10 '22 01:10

Максим Шатов