Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Forbid updating a django model field

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
like image 280
seblat Avatar asked Nov 02 '18 11:11

seblat


People also ask

How do you make a field non editable in Django admin?

editable=False will make the field disappear from all forms including admin and ModelForm i.e., it can not be edited using any form.

How do I override a Django model?

Whenever one tries to create an instance of a model either from admin interface or django shell, save() function is run. We can override save function before storing the data in the database to apply some constraint or fill some ready only fields like SlugField.

How do I update model fields in Django?

Method 2: Using F Expression You can also use the F expression to do the same job. Note: You have to import the F expression before using it. Basically, these are the two methods you can use to update field in Django model.

How can I remove extra's from Django admin panel?

You can add another class called Meta in your model to specify plural display name. For example, if the model's name is Category , the admin displays Categorys , but by adding the Meta class, we can change it to Categories . Literally saved my life!


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')
like image 69
Dougyfresh Avatar answered Oct 22 '22 12:10

Dougyfresh