Forbid updating a django model field

Viewed 2881

I have the following model:

class Project(models.Model):

    name = models.CharField(max_length=200)

class Task(models.Model):

    name = models.CharField(max_length=200)

    project = models.ForeignKey('Project', on_delete=models.CASCADE,
                                related_name='tasks')

I want to be able to choose the project for a task during creation and forbid to change it once the task was created.

How do I get Task.project to be editable during creation but non editable during updating on a database/model level?

Approaches so far:

  1. The editable=False option

    • This works on the admin/form level, not on the database level
  2. Making a field read-only in django admin

    • This also works on the admin/form level, no on the database level
1 Answers

Not sure about on the database level, but you could use a pre-save signal here and check that instance has a primary key, which will determine if this is the initial save or a modification. If its a modification you can raise an exception if the field has changed.

@receiver(pre_save, sender=Task)
def send_hook_on_roadmap_update(sender, instance, **kwargs):
    try:
        obj = sender.objects.get(pk=instance.pk)
    except sender.DoesNotExist:
        pass  # Initial save -- do nothing
    else:
        if not obj.project == instance.project:  # Field has changed
            raise models.ProtectedError('`project` should not be modified')
Related