我的问题与this one有点不同。我有一个与此模型相似的模型:
class Project(models.Model):
project_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True)
created_by_id = models.ForeignKey('auth.User', related_name='project', on_delete=models.SET_NULL, blank=True, null=True)
created_by = models.CharField(max_length=255, default="unknown")
created = models.DateTimeField(auto_now_add=True)
使用以下序列化器:
class ProjectSerializer(serializers.ModelSerializer):
created_by = serializers.ReadOnlyField(source='created_by_id.username')
class Meta:
model = Project
fields = ('project_id', 'created_by', 'created')
和相应的视图:
class projectsView(mixins.ListModelMixin,
mixins.CreateModelMixin,
generics.GenericAPIView):
queryset = Project.objects.all()
serializer_class = ProjectSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
def perform_create(self, serializer):
serializer.save(created_by_id=self.request.user)
此代码的行为与我想要的一样,但是会强制信息冗余,并且不会利用基础的关系数据库。我试图使用链接问题中的信息来实现“在数据库中写入用户ID,但在平面json中返回“ get”中的用户名”,但没有成功:
删除模型中的“ created_by”字段。将序列化器替换为:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
class ProjectSerializer(serializers.ModelSerializer):
created_by = UserSerializer(read_only=True)
created_by_id = serializers.PrimaryKeyRelatedField(
queryset=User.objects.all(), source='created_by', write_only=True)
class Meta:
model = Project
fields = ('project_id', 'created_by', 'created_by_id', 'created')
哪个不会100%给我我想要的东西,即用平面json中的用户名替换用户ID,但返回类似{'project_id': <uuid>, 'created_by': <user json object>, 'created': <data>}
的信息。但是我仍然遇到{'created_by_id': ['This field is required.']}
400错误。
问题:如何从request.user信息中将用户ID写入数据库对象,以引用实际的用户ID,但在projectView端点的GET请求中返回简单的用户名,而无需在模型中明确存储用户名?或更笼统地说,如何使用默认的序列化DRF功能和默认的DRF视图mixins将数据库对象(Django模型)序列化为客户json响应?
问题的替代表达:如何在模型中存储对另一个DB记录的ID引用(可以在不由有效负载提供的情况下访问它),但是在序列化器级别反序列化从该对象引用派生的信息,例如作为被引用对象的一个特定字段?
答案 0 :(得分:0)
我建议您将两个不同的序列化器用于Get
和POST
操作。将您的serializers.py
更改为
class ProjectGetSerializer(serializers.ModelSerializer):
created_by_id = serializers.StringRelatedField()
class Meta:
model = Project
fields = '__all__'
class ProjectCreateSerializer(serializers.ModelSerializer):
created_by_id = serializers.PrimaryKeyRelatedField(queryset=User.objects.all(), default=serializers.CurrentUserDefault())
def create(self, validated_data):
return Project.objects.create(**validated_data, created_by=validated_data['created_by_id'].username)
class Meta:
model = Project
fields = '__all__'
另外,如果您正在寻找ModelViewSet
,我建议将CRUD
operations用于API类。因此,视图将是这样,
class projectsView(viewsets.ModelViewSet):
queryset = Project.objects.all()
def get_serializer_class(self):
if self.action == 'create':
return ProjectCreateSerializer
return ProjectGetSerializer
因此,创建Project
的有效载荷是,
{
}
您在创建Project
用户时必须记住的一件事必须登录
更新-1
serializer.py
class ProjectCreateSerializer(serializers.ModelSerializer):
created_by_id = serializers.StringRelatedField()
class Meta:
model = Project
fields = '__all__'
def create(self, validated_data):
return Project.objects.create(**validated_data, created_by_id=self.context['request'].user)
views.py
class projectsView(viewsets.ModelViewSet):
queryset = Project.objects.all()
serializer_class = ProjectCreateSerializer
答案 1 :(得分:0)
该错误位于write_only字段选项中。 required
参数的默认值设置为True
,但如果我们看一下模型,其目的是使其不为必需。在此视图中,我将perform_create用作后期处理以保存在Model DB表示形式中。由于创建级别的required
默认值为True
,因此数据库的第一个.save()
失败。由于这纯粹是内部逻辑,因此不需要。因此,只需在required=False
上添加PrimaryKeyRelatedField
选项即可完成工作:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
class ProjectSerializer(serializers.ModelSerializer):
created_by = UserSerializer(read_only=True)
created_by_id = serializers.PrimaryKeyRelatedField(
queryset=User.objects.all(), source='created_by', write_only=True, required=False)
class Meta:
model = Project
fields = ('project_id', 'created_by', 'created_by_id', 'created')
如果我坚持纯粹在序列化器级别进行反序列化,那么在模型级别也必须执行require = True才能覆盖序列化器的.save函数。可能还有一种方法可以在序列化程序中获取用户ref,以使视图实现更加“默认” ...这可以通过使用Jerin中的默认值来完成:
class ProjectSerializer(serializers.ModelSerializer):
created_by = UserSerializer(read_only=True)
created_by_id = serializers.PrimaryKeyRelatedField(
queryset=User.objects.all(), source='created_by',
write_only=True,
required=False,
default=serializers.CurrentUserDefault())
class Meta:
model = Project
fields = ('project_id', 'created_by', 'created_by_id', 'created')
现在仅使用用户名来平整json,您需要使用一个Slug字段而不是UserSerializer:
class ProjectSerializer(serializers.ModelSerializer):
created_by = serializers.SlugRelatedField(
queryset=User.objects.all(), slug_field="username")
created_by_id = serializers.PrimaryKeyRelatedField(
queryset=User.objects.all(), source='created_by', write_only=True, required=False)
class Meta:
model = Project
fields = ('project_id', 'created_by', 'created_by_id', 'created')
然后只有用户模型的用户名字段值将显示在get有效负载上的create_by json标签上。
更新-1
经过一些调整之后,我得出了最终版本:
class ProjectSerializer(serializers.ModelSerializer):
created_by_id = serializers.PrimaryKeyRelatedField(
queryset=User.objects.all(), write_only=True, required=False, default=serializers.CurrentUserDefault())
created_by = serializers.SerializerMethodField('creator')
def creator(self, obj):
return obj.created_by_id.username
class Meta:
model = Project
fields = ('project_id', 'created_by_id', 'created_by', 'created')