【问题标题】:Django PrimaryKeyRelatedField queryset when allow_null=True当allow_null = True时的Django PrimaryKeyRelatedField查询集
【发布时间】:2017-10-22 01:01:28
【问题描述】:

我对 Python 和 Django 都很陌生,并且遇到了可以为空的外键关系的问题。我发现了与这个类似的问题,但似乎都没有涵盖我的用例。

我正在使用 Django 1.8.17 和 DRF 3.1.0

我在 Django 中有以下类(我已将它们简化为相关字段,因为我无法在此处轻松复制/粘贴我的代码):

class Rationale(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=255)

class Alert(models.Model):
    id = models.AutoField(primary_key=True)
    rationale = models.ForeignKey(Rationale, null=True, blank=True)
    priority = models.IntegerField(default=1)

class AlertHistory(models.Model):
    id = models.AutoField(primary_key=True)
    alert =  = models.ForeignKey(Alert)
    rationale = models.ForeignKey(Rationale, null=True, blank=True)
    priority = models.IntegerField(null=True)

class AlertHistoryListView(generics.ListCreateAPIView):
    queryset = AlertHistory.objects.all()
    serializer_class = AlertHistorySerializer
    pagination_class = DefaultPagination

    filter_backends = (filters.DjangoFilterBackend, filters.OrderingFilter)
    filter_class = AlertHistoryFilterSet
    filter_fields = ['alert']
    ordering_fields = filter_fields        

class AlertHistoryFilterSet(django_filters.FilterSet):
    class Meta:
        model = AlertHistory
        fields = ['alert']

这里的想法是在历史记录表中捕获对警报的更改。用户可以更新优先级或基本原理。

Rationale 表是使用 JSON 固定装置预先填充的查找表。用户可以选择一个基本原理来给出警报打开的原因。基本原理是可选的,因此可以为空。

但是,当我尝试将 Rationale 设置为 None 时出现错误:

{'rationale': [u'类型不正确。预期的 pk 值,收到的 unicode。']}

所以搜索导致我:PrimaryKeyRelatedField:http://www.django-rest-framework.org/api-guide/relations/#primarykeyrelatedfield

然后我更新了我的 AlertHistory 序列化程序:

class AlertHistorySerializer(serializers.ModelSerializer):
    rationale = serializers.PrimaryKeyRelatedField(read_only=True, allow_null=True)

    class Meta:
        model = AlertHistory

这解决了我的第一个问题,但在我更新基本原理的测试中导致了问题。通过将其标记为只读,毫无疑问我无法更新该字段。

文档说我需要指定 read_only=True 或查询集。但是它没有提供如何做到这一点的示例,我无法弄清楚或在任何地方找到任何示例。

我需要涵盖以下两种情况:

data = {'alert' : 1, 'priority' : 2, reasone: 1 } 将基本原理设置为基本原理 1 的外键。

还有:

data = {'alert' : 1, 'priority' : 2,rational: None } 如果用户想要将理由设置为空。当他们只是在没有选择理由的情况下更新优先级时,这种用例更有可能发生。

所以我尝试将我的查询集定义为“全部”

rationale = serializers.PrimaryKeyRelatedField(queryset=Rationale.objects.all(), allow_null=True)

但这会导致我的所有基本原理为 None 的测试都给出原始异常:

{'rationale': [u'类型不正确。预期的 pk 值,收到 unicode。']},即使我现在将 allow_null 设置为 True。

然后我尝试定义:

rationale = serializers.PrimaryKeyRelatedField(queryset=Rationale.objects.get(pk=rationale), allow_null=True)

但它不知道原理是什么。

我也试过了:

rationale = serializers.PrimaryKeyRelatedField(source='rationale', allow_null=True) 

但这导致我出错:

AssertionError:关系字段必须提供“queryset”参数,或设置 read_only=True

如何正确定义我的查询集?

谢谢。

【问题讨论】:

  • 你想让这个序列化程序从对象中获取数据并更新数据,不是吗?
  • 是的。我们需要能够查询历史表,以便我们可以显示随时间的变化。因此,在 /alerts/history 的获取将返回表格的内容,而对 /alerts/history 的帖子将让他们更改值。

标签: python django


【解决方案1】:

使用这个序列化器:

class AlertHistorySerializer(serializers.ModelSerializer):

    class Meta:
        model = AlertHistory

型号:

class AlertHistory(models.Model):
    id = models.AutoField(primary_key=True)
    alert =  = models.ForeignKey(Alert)
    rationale = models.ForeignKey(Rationale, null=True)
    priority = models.IntegerField(null=True)

用于创建警报历史对象的示例 json:

{
    "alert": 1,
    "rationale": null,
    "priority": 2
}

如果您想将理由设置为 null,请在 json 中发送 null

PS:确保您的数据库架构已更新并且所有迁移都已应用。

【讨论】:

  • 所以我的一些(全部?)问题可能是 Dict->JSON 转换问题。我正在使用 DRF 的 APIClient 类进行测试。 data = data = {'alert' : 1, 'priority' : 2,rational: None } APIClient().post('alerts/history', data) 也许它没有正确地将数据从 None 转换为 null?
  • 如果您将null 发送为None,则可能是。检查正确的 json 格式。上述解决方案是否解决了您的问题?
  • 没有。当我尝试在序列化程序中设置 fields = 'all' 时出现错误。
  • 我将编辑我的答案。实际上'__all__' 是最新的 DRF 版本。
  • 所以你的建议正是我所拥有的导致我最初的错误。这完全有可能只是一个测试问题。我不知道 APIClient 是如何转换我的字典的,但我尝试了 json.dumps(data) 并将我的 None 转换为 null,所以我不确定这是问题所在。目前,我通过仅在数据不是无时向数据添加基本原理来解决此问题,但这不是一个理想的解决方案。
猜你喜欢
  • 2016-08-13
  • 2021-11-23
  • 2013-07-05
  • 2012-12-31
  • 1970-01-01
  • 2013-04-27
  • 2016-09-03
  • 2015-07-03
  • 2015-12-23
相关资源
最近更新 更多