How to update the property of an instance of a model as foreign key of another model

Viewed 20

I have am in the following situation. I have a Django model that includes a link to another class, ex:

class Document(models.Model):

    document = models.FileField(upload_to=user_file_path)
    origin = models.CharField(max_length=9)
    date = models.DateField()
    company = models.ForeignKey(Company, on_delete=models.CASCADE)

Company includes a property called status. In another part of the code I am working with a doc of type Document and I want to update the status property of the company within the doc, so I proceed to:

doc.company.status = new_value
doc.save()

or

setattr(company, 'status', new_value)
company.save()

In the first case, the value of doc.company.status is updated, but if I query the company it keeps the old value, and in the second case is the other way around, the value of company.status is updated but doc.company.status keeps the old value. I had always assumed that updating either (doc.company or company) of them had an immediate effect over the other, but now it seems that doc has a copy of company (or some sort of lazy link difficult to foresee) and both remain separate, and both of them have to be updated to change the value. An alternative that seems to work is (saving doc.company instead of doc):

doc.company.status = new_value
doc.company.save()

The new value for status does not seem to propagate instantly to company, but yes when it is required by a query or operation. May someone explain the exact relationship or way of doing or provide a reference where I may find the proper explanations? Thanks

1 Answers

Setting an object instance attribute changes only the attribute on that instance. After using save(), the value is saved in the database.

If there were previously defined variables of the same instance, they will remain the same. That is, unless you call refresh_from_db() method.

Consider the following scenario:

company_var1 = Company.objects.get(pk=13)
company_var2 = Company.objects.get(pk=13)

company_var1.status = new_value  # This only changes the attribute on the model instance
print(company_var1.status)  # Output: new value
print(company_var2.status)  # Output: old value

company_var1.save()  # This updates the database table
print(company_var1.status)  # Output: new value
# Note how the company_var2 is still the same even though
# it refers to the same DB table row (pk=13).
print(company_var2.status)  # Output: old value

# After doing this company_var2 will get the values from the DB
company_var2.refresh_from_db()
print(company_var1.status)  # Output: new value
print(company_var2.status)  # Output: new value

I hope that clears things up and you can apply it to your case.

Related