Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django refresh_from_db for ForeignKey

Tags:

python

django

Is there a way to use refresh_from_db and automatically propagate it on ForeignKey ?

model.py:

class TestItemModel(models.Model):
  value = models.IntegerField(default=0)
  relies_on_item = models.ForeignKey('self', on_delete=models.SET_NULL, blank=True, null=True )

shell:

>>> end_product = TestItemModel(value=1)
>>> end_product.save()
>>> container_product = TestItemModel(value=10,relies_on_item=end_product)
>>> container_product.save()
>>> end_product.pk
12
>>> end_product_for_update=TestItemModel.objects.get(pk=12)
>>> end_product_for_update.value = 4
>>> end_product_for_update.save()
>>> container_product.relies_on_item.value
1
>>> container_product.refresh_from_db()
>>> container_product.relies_on_item.value
1

The value returned at this point is still the initial one. Is there an option to make refresh_from_db automatically cascade on elements referenced by ForeignKey?

It is possible to do it by explicitly using refresh_from_db on the referenced item - shown below. But I would like to only have to do refresh_from_db on container_product itself.

shell (continued):

>>> container_product.relies_on_item.refresh_from_db()
>>> container_product.relies_on_item.value
4
like image 224
Michel Laviron Avatar asked Mar 22 '17 08:03

Michel Laviron


People also ask

What is ForeignKey Django models?

Introduction to Django Foreign Key. A foreign key is a process through which the fields of one table can be used in another table flexibly. So, two different tables can be easily linked by means of the foreign key. This linking of the two tables can be easily achieved by means of foreign key processes.

What is __ str __ in Django?

str function in a django model returns a string that is exactly rendered as the display name of instances for that model.

How do I create a one to many relationship in Django?

To define a one to many relationship in Django models you use the ForeignKey data type on the model that has the many records (e.g. on the Item model).

How do I update a field in Django?

Use update_fields in save() If you would like to explicitly mention only those columns that you want to be updated, you can do so using the update_fields parameter while calling the save() method. You can also choose to update multiple columns by passing more field names in the update_fields list.


2 Answers

AFAIK In django, Till now refresh_from_db will not update data for relational fields.It only check whether relation is removed or not. But you can do like (as you did).

for i in container_product._meta.concrete_fields:
    if i.is_relation:
        getattr(container_product, i.name).refresh_from_db()

OR override refresh_from_db

class Mymodel(models.Model):
    def refresh_from_db(self, using=None, fields=None):
        super(Mymodel, self).refresh_from_db(using=None, fields=None)
        for i in self._meta.concrete_fields:
            if i.is_relation and getattr(self, i.name):
                getattr(self, i.name).refresh_from_db() 
like image 172
itzMEonTV Avatar answered Oct 24 '22 15:10

itzMEonTV


Another solution is to retrieve instance again from DB without using refresh_from_db.

instance = MyModel.objects.get(pk=pk)
like image 44
Szymon P. Avatar answered Oct 24 '22 15:10

Szymon P.