【问题标题】:How to hide field that is foreing key in serializer based on a statement如何根据语句隐藏序列化程序中的外键字段
【发布时间】:2021-11-16 00:57:27
【问题描述】:

这是我的序列化器

class SparkleTemplateSerializer(serializers.ModelSerializer):
    
    notifications = NotificationTemplateSerializer(source='notificationtemplate_set', many=True)
    rules = RuleTemplateSerializer(source='ruletemplate_set', many=True)   
    class Meta:
        model = SparkleTemplate
        fields = ['id', 'name', 'description', 'enabled', 'run_schedule', 'notifications', 'rules']

我需要显示和隐藏“通知”字段,如您所见,这是外键,但如果某些变量是真或假,则需要发生这种情况。

这就是我尝试的方法,通过将下面的代码添加到序列化程序中,但我猜它不起作用,因为 Meta 中的 fields 属性

def to_representation(self, obj):
        show = NotificationTemplate._meta.get_field('show')
        rep = super(SparkleTemplateSerializer, self).to_representation(obj)
        if show is False:
         rep.pop('notifications', None)
        return rep    

我还尝试排除“通知”并创建另一个序列化程序,但这不起作用,因为“通知”必须存在,所以我遇到了错误。谢谢

编辑 1: SparklesTemplate 模型

    company = models.ForeignKey(
        Company, on_delete=models.DO_NOTHING, blank=False, default=1)
    name = models.CharField(max_length=64, blank=False)
    description = models.CharField(max_length=256, blank=False, default="")
    enabled = models.BooleanField(default=False, blank=False)
    visible = models.BooleanField(default=True, blank=False)
    # sparkle must determine just how often it should run.
    # a cron string is the most flexible way to determine the schedule
    run_schedule = models.CharField(max_length=128, blank=False, default="*/15 * * * *",
                                    help_text="The cron formatted schedule that the notifications will trigger on.")


    # this will be appended to the end of the get visits query
    query_extra_arguments = models.CharField(max_length=256,
                                             blank=True,
                                             help_text="Extra arguments that will be added to the get visits query.")

    branch_owner = models.ForeignKey(Branch, on_delete=models.DO_NOTHING, blank=True, default=None, null=True, help_text="Dictates the visibility of the users.")

NotificationTemplate 模型:

    sparkle = models.ForeignKey(
        SparkleTemplate, on_delete=models.CASCADE, blank=False)

    enabled = models.BooleanField(default=True)
    show = models.BooleanField(default=True)
    class_name = models.ForeignKey(
        NotificationClass, on_delete=models.CASCADE, blank=False)
    class_args = models.TextField(max_length=16384, default="{}", blank=False)

另外,我在我的帖子中混淆了外键的方向,是相反的。

编辑 2 查看.py

class SparkleTemplateView(ListAPIView):

    serializer_class = SparkleTemplateSerializer

    def get_queryset(self):
        user = self.request.user
        
        return SparkleTemplate.objects.filter(branch_owner=user.branch)

【问题讨论】:

  • 你能分享你的模型吗?
  • @NielGodfreyPonciano 我做到了。另外,我现在不确定“pop”是否不起作用,因为“通知”最初不在 SparkleTemplate 模型中
  • 如果任何个实例show字段设置为False,您想从表示中删除NotificationTemplate实例吗?还是您只想显示showTrueNotificationTemplate 实例?
  • @NielGodfreyPonciano show 默认为 true,因此 NotifTemp 在为 true 时会显示,在通过管理面板设置为 false 时应隐藏。不,我只想隐藏显示字段设置为 false 的 NotifTemplates,但我可以使用过滤器修复它。
  • 你能展示一下你的观点吗?您可以使用与视图相关的预取并为 NotificationTemplate 提供查询集,它将仅获取 showTrue 的对象。

标签: python django django-rest-framework


【解决方案1】:

您可以将prefetch_related methodPrefetch object 一起使用,通常这用于解决N + 1 问题,但另一件事是允许为预取对象提供查询集。

因此您可以按如下方式修改视图:

from django.db.models import Prefetch


class SparkleTemplateView(ListAPIView):

    serializer_class = SparkleTemplateSerializer

    def get_queryset(self):
        user = self.request.user
        shown_notifications = NotificationTemplate.objects.filter(show=True)
        queryset = SparkleTemplate.objects.filter(
            branch_owner=user.branch
        ).prefetch_related(
            Prefetch('notificationtemplate_set', queryset=shown_notifications)
        )
        return queryset

现在您可以跳过修改序列化程序 to_representation,因为您已经过滤为仅显示所需的 NotificationTemplate 对象。

【讨论】:

    【解决方案2】:

    我们可以通过访问notifications 中每个项目的show 属性,从to_representation() 中删除结果字典中的元素。

    根据您希望通知的显示方式,这里有 2 个选项:

    • 选项-1:如果要删除所有notifications,如果至少1 个showFalse
    • 选项2:如果您只想删除notifications,其中showFalse
    def to_representation(self, obj):
        rep = super().to_representation(obj)
    
        # Option 1: If you want to remove all notifications if at least 1 show is False
        # if any(notif["show"] is False for notif in rep["notifications"]):
        #     del rep['notifications']  # Or rep.pop('notifications')
    
        # Option 2: If you only want to remove the notifications where show is False
        rep["notifications"] = list(filter(lambda notif: notif["show"], rep["notifications"]))
    
        return rep
    

    【讨论】:

    • 这引发了很多错误,就像我从序列化程序中的字段中完全删除“通知”字段时一样
    • 也许您同时添加了这两个选项?您可以尝试仅使用选项 2 吗?我已经用评论的选项 1 更新了我的答案以避免混淆,因为选项 2 似乎也是需要的。另外,抛出的错误是什么?
    • 不,不,我把第一个注释掉了,只试了第二个。
    • 抛出什么错误?实际上,我在我的机器上用你的模型和序列化程序的缩小版本尝试了这个并且工作(相关字段notifications 正确显示与True 显示)。可能是我的配置不足:)
    • 1st: ValueError: invalid literal for int() with base 10: 'lastframe' 2nd raise VariableDoesNotExist("Failed lookup for key" ...) KeyError 感谢您的帮助顺便说一句。最大的问题可能是我没有编写这段代码,所以可能在其他地方发生了一些我看不到的事情
    猜你喜欢
    • 2017-10-06
    • 1970-01-01
    • 1970-01-01
    • 2019-10-11
    • 2021-02-13
    • 1970-01-01
    • 2010-11-19
    • 2021-10-28
    • 2016-04-16
    相关资源
    最近更新 更多