Rahul
Rahul

Reputation: 115

How to update django model fields without knowing which fields to be updated beforehand?

I want to update a model without knowing which fields to update beforehand. For example: The request to my url api/user/(?P<pk>[0-9]+)/message-update/(?P<id>[0-9]+)/ will have a payload JSON with a POST request method like this:

{
"category": "personal",
"type_of_transaction": "paid"
}

The problem here is that the payload key-value pairs will keep changing depending upon the fields to be changed.

I have tried this but it seems to have no effect at all:

message = Message.objects.get(user=pk, id=id)
json_data = json.loads(request.body.decode(encoding='UTF-8'))
attributes_to_be_changed = json_data.keys()
values = json_data.values()
for i in attributes_to_be_changed:
    message.i = values[attributes_to_be_changed.index(i)]
message.save(update_fields=attributes_to_be_changed)
try:
    json_message = MessageSerializer(Message, many=False)
except Exception as e:
    return JsonResponse({"error": e})
return JsonResponse(json_message.data, safe=False)

I have a message model as below:

user = models.ForeignKey(User, related_name='messages')
sender = models.CharField(max_length=15, blank=True)
body = models.CharField(max_length=400, blank=True)
account = models.ForeignKey(Account, blank=True, null=True)
card = models.ForeignKey(CreditCard, blank=True, null=True)
type_of_transaction = models.CharField(max_length=10)
message_date = models.DateTimeField(blank=True, null=True)
category = models.CharField(max_length=15, blank=True)
spent_at = models.CharField(max_length=15, blank=True)
meta = models.CharField(max_length=30, blank=True)
amount = models.FloatField()
lat = models.CharField(max_length=50, default="null")
lon = models.CharField(max_length=50, default="null")

def __str__(self):
    try:
        state = "Message from "+self.account.name+" for "+self.user.username
    except Exception:
        state = "Message from "+ self.card.card_number+"for"+self.user.username
    return state

My serializer:

class MessageSerializer(serializers.ModelSerializer):
    account = serializers.SerializerMethodField()

    def get_account(self, obj):
        try:
            name = obj.account.name
        except Exception:
            name = obj.card.card_number
        return name

    class Meta:
        model = Message
        fields = ('id','sender','body','account','category','spent_at','meta','type_of_transaction', 'amount', 'message_date')

Upvotes: 0

Views: 1002

Answers (3)

Brian Ocampo
Brian Ocampo

Reputation: 1524

You can do the following:

# Note: if id field is primary key, you don´t need to consult by user also

message_updated = Message.objects.filter(user=pk, id=id).update(**json_data)

Upvotes: 0

Rahul
Rahul

Reputation: 115

Got it! It was a typo in json_message = MessageSerializer(Message, many=False). Replaced Message with message and got it working. It was previously taking the model as an argument.

Upvotes: 0

Basalex
Basalex

Reputation: 1187

Well, I think in your case you should use setattr

for key, value in json_data.items():
    setattr(message, key, value)

Or maybe update_or_create could be a good idea, too https://docs.djangoproject.com/en/2.0/ref/models/querysets/#update-or-create

defaults is your json_data

Upvotes: 1

Related Questions