[Python] How to force a Django model to reload fields after saving without using...

Discussão em 'Python' iniciado por Stack, Junho 6, 2025.

  1. Stack

    Stack Membro Participativo

    I have the following Django models: Device had a foreign key to Deployment I have the adopt method in Device that set the deployment for a device and perform some additional logic.

    notice that I pass an id and not a Deployment instance to the adopt method

    class Device(Model):
    id = models.UUIDField(primary_key=True)
    deployment = models.ForeignKey(
    Deployment, on_delete=models.SET_NULL, blank=True, null=True, related_name='devices'
    )

    def adopt(self, deployment_id):
    self.deployment_id = deployment_id
    self.full_clean()

    with transaction.atomic():
    self.save()

    # self.refresh_from_db()

    if self.deployment.private: # this might fail.. see examples
    # additional logic
    pass


    class Deployment(TimeStampedModel, DeploymentResource):
    id = models.UUIDField(primary_key=True)
    name = models.CharField(max_length=150)
    private = models.BooleanField(default=False)



    If I do not access to the deployment field of the Device instance, adopt() works as expected. example:

    device = Device.objects.get(pk=device_id)
    device.adopt(deployment_id) # this works


    if instead I load the deployment field before calling adopt, when I call Adopt I get an AttributeError: 'NoneType' object has no attribute 'private'

    this does not works:

    device = Device.objects.get(pk=device_id)
    print(device.deployment) # example of accessing/loading the field/relation
    device.adopt(deployment_id) # this will generate the attribute error


    The cause is pretty obvious. device.deployment was None, its value has been loaded and stored inside the model but it's not automatically reloaded and substituted with the new deployment after the save() call. The first example works simply because the deployment relation has never been accessed before the save.

    An obvious solution is to call refresh_from_db after saving (see comment inside adopt method) but this will generate an additional query that I would like to avoid. Is there a way to force the model to forget the "cached" value of the deployment attribute that does not involve an additional query?

    edit: clarified where the exception is raised

    Continue reading...

Compartilhe esta Página