我很困惑如何在DRF中的序列化器和视图中实现方法:
我有一个扩展AbstractBaseUser的帐户模型。视图集如下所示:
class AccountViewSet(viewsets.ModelViewSet):
lookup_field = 'username'
queryset = Account.objects.all()
serializer_class = AccountSerializer
def get_permissions(self):
if self.request.method in permissions.SAFE_METHODS:
return (permissions.AllowAny(), TokenHasReadWriteScope())
if self.request.method == 'POST':
return (permissions.AllowAny(), TokenHasReadWriteScope())
return (permissions.IsAuthenticated(), IsAccountOwner(), TokenHasReadWriteScope())
def create(self, request):
serializer = self.serializer_class(data=request.data)
if serializer.is_valid():
Account.objects.create_user(**serializer.validated_data)
return Response(serializer.validated_data, status=status.HTTP_201_CREATED)
return Response({
'status': 'Bad request',
'message': 'Account could not be created with received data.'
}, status=status.HTTP_400_BAD_REQUEST)
这样的序列化器:
class AccountSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=False)
confirm_password = serializers.CharField(write_only=True, required=False)
class Meta:
model = Account
fields = ('id', 'email', 'username', 'created_at', 'updated_at',
'first_name', 'last_name', 'tagline', 'password',
'confirm_password',)
read_only_fields = ('created_at', 'updated_at',)
def create(self, validated_data):
return Account.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.username = validated_data.get('username', instance.username)
instance.save()
password = validated_data.get('password', None)
confirm_password = validated_data.get('confirm_password', None)
if password and confirm_password:
instance.set_password(password)
instance.save()
update_session_auth_hash(self.context.get('request'), instance)
return instance
def validate(self, data):
if data['password'] and data['confirm_password'] and data['password'] == data['confirm_password']:
try:
validate_password(data['password'], user=data['username']):
return data
except ValidationError:
raise serializers.ValidationError("Password is not valid.")
raise serializers.ValidationError("Passwords do not match.")
在视图的create方法上,它检查序列化程序是否有效,然后保存并根据结果返回响应。我的第一个问题是什么时候调用序列化器create()方法?对我来说,似乎通过在视图的create()方法中调用create_user(模型方法)来完全绕过该方法。它会被调用吗?有什么意义呢?
其次,我无法从更新方法返回状态代码,实例保存在序列化程序中。如果验证失败,串行器update()中的代码是否会起作用?
这是我到目前为止所做的:
def update(self, request, pk=None):
serializer = self.serializer_class(data=request.data)
if serializer.is_valid():
<< what goes here??? >>
return Response(serializer.validated_data, status=status.HTTP_200_OK)
except serializers.ValidationError as e:
return Response({
'status': 'Bad request',
'message': str(e)
}, status=status.HTTP_400_BAD_REQUEST)
return Response({
'status': 'Bad request',
'message': 'Account could not be updated with received data.'
}, status=status.HTTP_400_BAD_REQUEST)
我迫切需要一些澄清。我不确定如何通过视图/序列化方法请求流程,我不知道如何在序列化程序中保存实例并决定在视图中同时返回哪个响应。
编辑:
我删除了create
和update
方法并修复了get_permissions
AccountViewSet
,并按照您的建议将validate
添加了用户名验证。我还更新了序列化器的创建和更新方法,以下是新版本:
def create(self, validated_data):
instance = super(AccountSerializer, self).create(validated_data)
instance.set_password(validated_data['password'])
instance.save()
return instance
def update(self, instance, validated_data):
instance.username = validated_data.get('username', instance.username)
password = validated_data.get('password', None)
confirm_password = validated_data.get('confirm_password', None)
if password and confirm_password:
instance.set_password(password)
instance.save()
update_session_auth_hash(self.context.get('request'), instance)
else:
instance.save()
return instance
我唯一的问题是,是否有必要在set_password
之后致电create
? create
是否为新用户设置了密码?在create
和update
的视图中没有代码可以吗?在没有查看代码的情况下调用serializer.save()
的位置以及序列化程序validate
何时运行而不调用serializer.is_valid()
?
答案 0 :(得分:4)
在create()
类的AccountViewSet
方法中,当序列化程序验证通过时,您正在创建Account
实例。相反,你应该打电话给serializer.save()
。
如果您查看save()
课程中的BaseSerializer
方法,您会看到它调用create()
或update()
方法,具体取决于模型实例是否正在创建或更新。由于您未在serializer.save()
方法中调用AccountViewSet.create()
,因此未调用AccountSerializer.create()
方法。希望这能回答你的第一个问题。
你的第二个问题的答案是缺少serializer.save()
。将<< what goes here??? >>
替换为serializer.save()
。这(如上所述)将调用AccountSerializer.update()
方法。
答案 1 :(得分:3)
<强> AccountViewSet 强>:
从您的示例中,您不需要.create()
和.update()
方法 - 现有方法应该足够了
get_permissions()
- 首先&#34;如果&#34;正在打开你的系统太宽了imho应该删除 - 你允许任何人做POST
- &#34;又名&#34;创建新帐户,这没关系,但其他所有内容(例如GET
或PUT
) - 只应该允许帐户所有者或(如果有需要!)注册用户
<强> AccountSerializer 强>:
id
字段是只读的,您不希望有人覆盖现有用户现有create()
方法可以删除,但我认为您应该看起来像这样:
def create(self, validated_data):
instance = super(AccountSerializer, self).create(validated_data)
instance.set_password(validated_data['password'])
instance.save()
return instance
现有update()
方法......不确定您想要什么,但是:
username
字段中的内容,它可能是空字符串或无 - 只有在密钥时才会调用dictionary.get
上的后备字典中缺少username
的唯一性(模型&#39;字段定义中的唯一= True) - 您将获得奇怪的异常,而不是API的错误消息)validate
方法update_fields
传递给save()
以限制更新哪些字段? validation
- 只需添加username
次验证;)
只是为了快速了解DRF(非常简化) - Serializers
是API Forms
,ViewSets
- 通用Views
,渲染器是templates
(决定数据的显示方式)
- 编辑 -
有关视图集的更多项目,ModelViewSet包含: