Django POST 验证字段消失(NOT NULL 约束失败)
Django POST validated fields disappearing (NOT NULL constraint failed)
我有一个包含一些模型的 Django 项目。给我带来麻烦的是这个:
class Job(models.Model):
patient = models.CharField(max_length=64, null=False, blank=False)
how = MultiSelectField(choices=HOW_CHOICES, default=1)
with_who = MultiSelectField(choices=WITH_WHO_CHOICES, default=1)
accessories = MultiSelectField(choices=ACCESSORIES, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True, null=False, blank=False)
scheduled = models.DateTimeField(null=True, blank=True)
arrived = models.DateTimeField(null=True, blank=True)
started = models.DateTimeField(null=True, blank=True)
completed = models.DateTimeField(null=True, blank=True)
scheduled_end = models.DateTimeField(null=True, blank=True)
detected_end = models.DateTimeField(null=True, blank=True)
approved = models.BooleanField(default=False)
area_start = models.ForeignKey(Area, on_delete=models.CASCADE, null=False, related_name='jobs_start')
area_end = models.ForeignKey(Area, on_delete=models.CASCADE, null=False, related_name='jobs_end')
comment = models.CharField(max_length=256, null=True, blank=True)
worker = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='jobs_worker')
我有这个 URL 可以进行 GET、POST、PUT 和 DELETE。
router.register(r'jobs', views.JobList)
链接到的视图继承自 ModelViewSet:
class JobList(LoginRequiredMixin, viewsets.ModelViewSet):
queryset = Job.objects.all()
serializer_class = JobsSerializer
根据我的理解,只需从 ModelViewSet 继承,API 默认处理 GET、POST 和 PUT。这可能就是为什么在网络 API 中我看到数据为 POST (see this screenshot) 的表单。该视图完美地处理了 GET,但问题出在 POST 请求。
如您在 screenshot 中所见,POST 数据只有 3 个字段需要填写。但是在模型中,我声明了更多字段 null=False
,这与 POST 数据框中的字段不同。所以,一个问题是:
- API从哪里获取需要显示的字段信息?
如果我尝试 POST,我会得到这个错误:
NOT NULL constraint failed: job_manager_job.area_end_id
我将 create() 函数添加到视图和序列化程序以调试 API 进程。此时我手动添加了一些创建作业所需的字段 (see this other screenshot)。如您所见,我在两个相似的键中添加了相同的值,这又引出了另一个问题:
- JSON 需要哪些键?模型的字段名称或序列化程序中的字段?
视图如下所示:
class JobList(LoginRequiredMixin, viewsets.ModelViewSet):
queryset = Job.objects.all()
serializer_class = JobsSerializer
def create(self, request, *args, **kwargs):
json_data = request.data
job_serializer = self.serializer_class(data=json_data)
if job_serializer.is_valid():
job_serializer.save()
print("valid data")
pass
序列化程序是这样的:
class JobsSerializer(serializers.ModelSerializer):
status = serializers.SerializerMethodField('get_status')
area_from = serializers.StringRelatedField(source='area_start.name', default=None)
area_to = serializers.StringRelatedField(source='area_end.name', default=None)
assigned = serializers.SerializerMethodField('get_assigned')
info = serializers.SerializerMethodField('get_info')
def create(self, validated_data):
print(validated_data)
Job.objects.create(**validated_data)
pass
def get_status(self, a_job):
if a_job.approved:
return 'Approved'
if a_job.completed:
return 'Completed'
if a_job.started:
return 'Started'
if a_job.arrived:
return 'Arrived'
if a_job.scheduled:
return 'Scheduled'
if a_job.created:
return 'Created'
return 'Defined'
def get_info(self, a_job):
return get_job_info_options(a_job)
def get_assigned(self, a_job):
try:
a = a_job.worker.first_name + ' ' + a_job.worker.last_name
except AttributeError:
a = None
return a
class Meta:
model = Job
fields = ['pk', 'status', 'scheduled', 'scheduled_end', 'assigned', 'area_from', 'area_to', 'patient', 'info']
问题是在调试器中,我看到视图接收到所有 JSON 数据(包括额外的键),这些数据在 self.serializer_class(data=json_data)
中传递给序列化程序,但是 validated_data 在序列化器中只包含 POST box.I 中显示的 3 个键不知道这些数据是如何在序列化器中消失的。
检查 this screenshot 可以看到序列化器的 data={...}
与 create 函数中的 validated_data
不同
我将不胜感激,不仅解决了这个问题,而且如果有人能回答上面关于 django 内部如何工作的问题。
提前致谢。
一起来看看:
fields = [
'pk', # unused in create
'status', # on serializer, read only method field
'scheduled', # OK
'scheduled_end', # OK
'assigned', # on serializer, read only method field
'area_from', # on serializer, read only string related field
'area_to', # on serializer, read only string related field
'patient', # OK
'info' # on serializer, read only method field
]
我有 3 个 OK,所以我认为 DRF 是正确的:)
问题:
- API从哪里获取需要显示的字段信息?
serializer.Meta.fields 中的所有可写字段最终都会出现在表单中。它们不一定是表单呈现它们所必需的。
- JSON 需要哪些键?模型的字段名称或序列化程序中的字段?
序列化程序的字段名称。但更准确地说,Parsers are first in the pipeline, which allows you to send camelCase json and get snake_case in validated data.
解决您问题的最简单方法是PrimaryKeyRelatedField. This means consumer needs to remember primary keys, but SlugRelatedField 可以使内容保持可读性。
我有一个包含一些模型的 Django 项目。给我带来麻烦的是这个:
class Job(models.Model):
patient = models.CharField(max_length=64, null=False, blank=False)
how = MultiSelectField(choices=HOW_CHOICES, default=1)
with_who = MultiSelectField(choices=WITH_WHO_CHOICES, default=1)
accessories = MultiSelectField(choices=ACCESSORIES, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True, null=False, blank=False)
scheduled = models.DateTimeField(null=True, blank=True)
arrived = models.DateTimeField(null=True, blank=True)
started = models.DateTimeField(null=True, blank=True)
completed = models.DateTimeField(null=True, blank=True)
scheduled_end = models.DateTimeField(null=True, blank=True)
detected_end = models.DateTimeField(null=True, blank=True)
approved = models.BooleanField(default=False)
area_start = models.ForeignKey(Area, on_delete=models.CASCADE, null=False, related_name='jobs_start')
area_end = models.ForeignKey(Area, on_delete=models.CASCADE, null=False, related_name='jobs_end')
comment = models.CharField(max_length=256, null=True, blank=True)
worker = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='jobs_worker')
我有这个 URL 可以进行 GET、POST、PUT 和 DELETE。
router.register(r'jobs', views.JobList)
链接到的视图继承自 ModelViewSet:
class JobList(LoginRequiredMixin, viewsets.ModelViewSet):
queryset = Job.objects.all()
serializer_class = JobsSerializer
根据我的理解,只需从 ModelViewSet 继承,API 默认处理 GET、POST 和 PUT。这可能就是为什么在网络 API 中我看到数据为 POST (see this screenshot) 的表单。该视图完美地处理了 GET,但问题出在 POST 请求。
如您在 screenshot 中所见,POST 数据只有 3 个字段需要填写。但是在模型中,我声明了更多字段 null=False
,这与 POST 数据框中的字段不同。所以,一个问题是:
- API从哪里获取需要显示的字段信息?
如果我尝试 POST,我会得到这个错误:
NOT NULL constraint failed: job_manager_job.area_end_id
我将 create() 函数添加到视图和序列化程序以调试 API 进程。此时我手动添加了一些创建作业所需的字段 (see this other screenshot)。如您所见,我在两个相似的键中添加了相同的值,这又引出了另一个问题:
- JSON 需要哪些键?模型的字段名称或序列化程序中的字段?
视图如下所示:
class JobList(LoginRequiredMixin, viewsets.ModelViewSet):
queryset = Job.objects.all()
serializer_class = JobsSerializer
def create(self, request, *args, **kwargs):
json_data = request.data
job_serializer = self.serializer_class(data=json_data)
if job_serializer.is_valid():
job_serializer.save()
print("valid data")
pass
序列化程序是这样的:
class JobsSerializer(serializers.ModelSerializer):
status = serializers.SerializerMethodField('get_status')
area_from = serializers.StringRelatedField(source='area_start.name', default=None)
area_to = serializers.StringRelatedField(source='area_end.name', default=None)
assigned = serializers.SerializerMethodField('get_assigned')
info = serializers.SerializerMethodField('get_info')
def create(self, validated_data):
print(validated_data)
Job.objects.create(**validated_data)
pass
def get_status(self, a_job):
if a_job.approved:
return 'Approved'
if a_job.completed:
return 'Completed'
if a_job.started:
return 'Started'
if a_job.arrived:
return 'Arrived'
if a_job.scheduled:
return 'Scheduled'
if a_job.created:
return 'Created'
return 'Defined'
def get_info(self, a_job):
return get_job_info_options(a_job)
def get_assigned(self, a_job):
try:
a = a_job.worker.first_name + ' ' + a_job.worker.last_name
except AttributeError:
a = None
return a
class Meta:
model = Job
fields = ['pk', 'status', 'scheduled', 'scheduled_end', 'assigned', 'area_from', 'area_to', 'patient', 'info']
问题是在调试器中,我看到视图接收到所有 JSON 数据(包括额外的键),这些数据在 self.serializer_class(data=json_data)
中传递给序列化程序,但是 validated_data 在序列化器中只包含 POST box.I 中显示的 3 个键不知道这些数据是如何在序列化器中消失的。
检查 this screenshot 可以看到序列化器的 data={...}
与 create 函数中的 validated_data
不同
我将不胜感激,不仅解决了这个问题,而且如果有人能回答上面关于 django 内部如何工作的问题。
提前致谢。
一起来看看:
fields = [
'pk', # unused in create
'status', # on serializer, read only method field
'scheduled', # OK
'scheduled_end', # OK
'assigned', # on serializer, read only method field
'area_from', # on serializer, read only string related field
'area_to', # on serializer, read only string related field
'patient', # OK
'info' # on serializer, read only method field
]
我有 3 个 OK,所以我认为 DRF 是正确的:)
问题:
- API从哪里获取需要显示的字段信息?
serializer.Meta.fields 中的所有可写字段最终都会出现在表单中。它们不一定是表单呈现它们所必需的。
- JSON 需要哪些键?模型的字段名称或序列化程序中的字段?
序列化程序的字段名称。但更准确地说,Parsers are first in the pipeline, which allows you to send camelCase json and get snake_case in validated data.
解决您问题的最简单方法是PrimaryKeyRelatedField. This means consumer needs to remember primary keys, but SlugRelatedField 可以使内容保持可读性。