Taylor
Taylor

Reputation: 1253

Why does the attribute get set but does not persist

I am trying to dynamically add an attribute to at runtime using the following snippets of code:

View

...
for appellation in queryset:
  if appellation.id in used_id_set:
    appellation.is_used_flag()
    print(appellation.is_used)
    # prints true as expected
  else:
    appellation.is_not_used_flag()

  first = queryset.first()
  print(first.is_used)
  # prints AttributeError: 'Appellation' object has no attribute 'is_used'

In Model

...
def is_used_flag(self):
  self.is_used = True
def is_not_used_flag(self):
  self.is_used = False

Why does it work correctly when in the loop but when I try to retrieve the attribute from an instance after it does not work? I have run into the same issue using setattr, appellation.is_used = True and modifying __dict__. Also is there a better way to do this?

I have referenced these posts:
Why can't you add attributes to object in python? I do have a dict but it does not seem to "persist" after the loop

How to assign a new class attribute via __dict__? Same issue as mentioned above

Dynamically defining instance fields in Python classes Same as above

Update

Since both answers mention similar things, I should clarify what my intentions are. I do not want to actually persist the value in the DB. I just want to serialize it and use it in the front end.

Upvotes: 0

Views: 169

Answers (2)

Lucas Lavandeira
Lucas Lavandeira

Reputation: 71

The Queryset API in django (often) returns other querysets, which are in turn evaluated by accessing the database. By doing queryset.first() you're executing another database call, where your attributes have not been yet set.

If you need to save this is_used flag between querysets (persist the change), I suggest you add a BooleanField on your model, or perhaps find another way to do what you want, as in memory attributes will not get returned by using the queryset API.

Upvotes: 1

Jamie Williams
Jamie Williams

Reputation: 347

If you want the change to persist you will need to call self.save() after setting is_used, assuming that is_used is a field on the Appellation model.

models.py

from django.db import models

class Appellation(models.Model):
    # ... rest of code ...

    is_used = models.BooleanField(default=False)

    def is_used_flag(self):
        self.is_used = True
        self.save()

    def is_not_used_flag(self):
        self.is_used = False
        self.save()

Note that Django instances are still Python objects so adding an attribute dynamically will work in the same way, this is why it prints True as expected in the code you provided.

Upvotes: 0

Related Questions