此QueryDict实例是不可变的

Row*_*jon 5 django django-models django-rest-framework

我有一个带有外键帐户的分支模型(分支的所有者):

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'),)

    ...
Run Code Online (Sandbox Code Playgroud)

我有一个带有用户外键的帐户模型(一对一字段):

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')
Run Code Online (Sandbox Code Playgroud)

我为分支创建了ModelViewSet,它显示了登录用户拥有的分支:

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
Run Code Online (Sandbox Code Playgroud)

现在要创建一个新分支,我想使用request.user.account保存帐户字段,而不是使用其余客户端发送的数据保存帐户字段(以提高安全性)。例如:

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)
Run Code Online (Sandbox Code Playgroud)

在分支序列化器中

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')
            )
        ]
Run Code Online (Sandbox Code Playgroud)

但我收到此错误:此QueryDict实例是不可变的。(意味着request.data是一个不变的QueryDict,不能更改)

您是否知道使用django rest框架创建对象时添加其他字段的更好方法?

小智 11

做简单:

#views.py
from rest_framework import generics


class Login(generics.CreateAPIView):
    serializer_class = MySerializerClass
    def create(self, request, *args, **kwargs):
        request.data._mutable = True
        request.data['username'] = "example@mail.com"
        request.data._mutable = False

#serializes.py
from rest_framework import serializers


class MySerializerClass(serializers.Serializer):
    username = serializers.CharField(required=False)
    password = serializers.CharField(required=False)
    class Meta:
        fields = ('username', 'password')
Run Code Online (Sandbox Code Playgroud)


小智 10

request.data._mutable=True
Run Code Online (Sandbox Code Playgroud)

将 mutable 设置为 true 以启用在 querydict 或请求中进行编辑。


Мак*_*тов 8

如您在Django文档中所见:

所述QueryDictsrequest.POSTrequest.GET中在访问时将是不可变的正常请求/响应循环

因此您可以使用同一文档中的建议:

要获得可变版本,您需要使用QueryDict.copy()

或...使用一些小技巧,例如,如果出于某种原因需要保留对对象的引用或使对象保持不变:

# 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
Run Code Online (Sandbox Code Playgroud)

数据在哪里是您的QueryDicts


Lin*_*via 3

您知道使用 django Rest 框架创建对象时添加附加字段的更好方法吗?

创建/更新对象时提供额外数据的官方方法是将它们传递给如下serializer.save()所示

  • 当需要验证属性时,这没有帮助。`is_valid()` 在 `.save()` 之前调用 (5认同)