Home > Back-end >  How to hide field that is foreing key in serializer based on a statement
How to hide field that is foreing key in serializer based on a statement

Time:09-23

This is my serializer

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']

I need to show and hide "notifications" field which is foreign key as you can see, but that need to happen if some variable is true or false.

This is how I tried to do it, by adding the code below to a serializer, but I guess it doesn't work cuz of the fields property in Meta

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    

I also tried excluding "notifications" and creating another serializer, but that doesn't work cuz "notifications" has to be there, so I was getting errors. Thanks

EDIT 1: SparklesTemplate model

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 model:

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)

Also, I mixed up the direction of the foreign key in my post, it's the opposite.

EDIT 2 View.py

class SparkleTemplateView(ListAPIView):

    serializer_class = SparkleTemplateSerializer

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

CodePudding user response:

We can remove the elements in the resulting dictionary from to_representation() by accessing the show attribute of each item in the notifications.

Depending on how you want the notifications to show, here are 2 options:

  • Option-1: If you want to remove all notifications if at least 1 show is False
  • Option-2: If you only want to remove the notifications where show is False
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

CodePudding user response:

You can use the prefetch_related method with a Prefetch object, normally this is used to solve the N 1 problem but another thing is allows is to provide a queryset for the prefetched object.

Hence you can modify your view as follows:

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

Now you can skip modifying the serializers to_representation as you have already filtered to only show the required NotificationTemplate objects.

  • Related