Arbazz Hussain
Arbazz Hussain

Reputation: 1932

How to update the field of django model from the existing field on the Fly

How to update the field of django model by taking/extracting values or filtering values from existing field of same object?

I have the following model:

from django.contrib.postgres.fields import JSONField,ArrayField

class MyUrlModel(models.Model):
    urls_json_data = JSONField(blank=True,null=True,default=dict)
    urls_list = ArrayField(models.TextField(blank=True),blank=True,null=True,default=list)

field urls_json_data has the following data in json:

[{"protocol":"http","hostname":"google.com","port":80"},{"protocol":"https","hostname":"apple.com","port":443"}]

Here, i would like to fetch the structures from urls_json_data and make it into url structure like following and save them under urls_list which is ArrayField.

urls_list=['http://google.com:80','https://apple.com:443']

So whenever urls_json_data get's updated, I want to fetch the URLs from it and save it under urls_list on the fly. What is the best approach to do it, is it by signals or by altering save method?

urls_list = []
for each_data in urls_json_data:
  url = each_data['protocol']+each_data['hostname']+each_data['port']
  urls_list.append(url)

Upvotes: 1

Views: 452

Answers (2)

heemayl
heemayl

Reputation: 41987

Generally speaking, whenever you find yourself in a situation that one field depends on the value of another field, most of the time it's a better idea to make the dependent field an attribute e.g. using the property descriptor.

In your case, you should make urls_list a property:

class MyUrlModel(models.Model):
    urls_json_data = JSONField(blank=True,null=True,default=dict)

    @property
    def urls_list(self):
        # Parse `self.urls_json_data` and return

Now from any instance of the model, you can refer to the value by <instance>.urls_list.

If you think urls_list is computationally expensive, then you can make it a method e.g. get_urls_list instead to make sure the users do not think of urls_list like a cheap field access.


If you insist on using urls_list as a field that depends on the current value of urls_json_data, you can override save method of the model and do the operations there before saving the field e.g.:

class MyUrlModel(models.Model):
    urls_json_data = JSONField()
    urls_list = ArrayField()

    def save(self, *args, **kwargs):
        # `self.get_from_urls_json_field()` is a placeholder
        # for the actual operations to be done
        self.urls_list = self.get_from_urls_json_field()
        super().save(*args, **kwargs)

Upvotes: 1

Iain Shelvington
Iain Shelvington

Reputation: 32244

You may not even need to store the data, you can add a property that will return the URLs dynamically

class MyUrlModel(models.Model):
    urls_json_data = JSONField(blank=True,null=True,default=dict)

    @property
    def urls_list(self):
        return ['{protocol}{hostname}{port}'.format(**url) for url in self.urls_json_data]

Upvotes: 1

Related Questions