Reputation: 1932
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
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
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