Home > other >  Default values in model property based on another property in the same model django
Default values in model property based on another property in the same model django

Time:02-16

I want to send default values based on another key in the same model and I'm using Django with Postgres, for example, if the type = 'owner' || 'admin' so the can_edit property should be true otherwise it should be false.

models.py

class Type(models.Model):
   name = models.CharField(max_length=255)


class Role(models.Model):
   name = models.CharField(max_length=255)
   type = models.ForeignKey(Type, on_delete=models.CASCADE, null=True)
   can_edit = models.BooleanField(null=True)

serializers.py

class RoleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Role
        fields = ['id', 'name', 'type', 'can_edit']

views.py

@api_view(['POST', 'GET'])
def roles_handler(request):
    if request.method == 'POST':
        role = RoleSerializer(data=request.data)
        role.is_valid(raise_exception=True)
        role.save()
        return Response({'data': role.data, 'success': True})

CodePudding user response:

You need to override the save method on 'Role' class in models.py Add this in models.py under class Role

def save(self, *args, **kwargs):
        if self.type.name == 'owner' or self.type.name == 'admin':
            self.can_edit = True
        super(Role, self).save(*args, **kwargs)

If you want to set 'can_edit' to False otherwise then edit the line

can_edit = models.BooleanField(null=True)

to

can_edit = models.BooleanField(default=False)

CodePudding user response:

like Bartosz Stasiak said. You can use a pre_save signal which is called before saving the data to the database.

First, create a new signals.py file in your directory.

write as follows:

from django.db.models.signals import pre_save
from django.dispatch import receiver
from .app import Role #import your model here

@receiver(pre_save, sender=Role) # in sender you have to put the model where the pre_save function is called
def validate_can_edit(sender, instance, *args, **kwargs):
     if instance.type.casefold() in ['owner', 'admin']:  #checking if values are equal and convert the input value to lowercase to avoid case-sensitive issues.
        instance.can_edit = True
     else:
        instance.can_edit = False

in your serializers.py remove can_edit field as you won't need it anymore and will be assigned by the signal function before saving to database.

class RoleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Role
        fields = ['id', 'name', 'type']

CodePudding user response:

You can use for example pre_save signal

from django.db.models.signals import pre_save
from django.dispatch import receiver

@receiver(pre_save, sender=Role)
def validate_can_edit(sender, instance, *args, **kwargs):
     if instance.type.name == 'admin':
        can_edit = True

But I want to suggest different solution. Move can_edit flag to Type model like this:

class Type(models.Model):
   name = models.CharField(max_length=255)
   can_edit = models.BooleanField(null=True)


class Role(models.Model):
   name = models.CharField(max_length=255)
   type = models.ForeignKey(Type, on_delete=models.CASCADE, null=True)
   

This way you can access can_edit flag using type.can_edit AND you will not lose this functionality when renaming Type to different name like from admin to Admin

  • Related