has_changed incompatible with model with vector_fields
Opened this issue · 5 comments
I just added a django-pgvector VectorField to my model and am now having an issue with using has_changed
.
The error is ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
.
The source of the error is /mixins.py", line 91, in _diff_with_initial
This doesn't happen if is_changed=False but if True then every field in the model is checked for changes.
I think there are two issues here:
- The check for changes should cope with the case where the field value is a vector/list
- The check for changes should only be applied to the fields in when_any, not to all field
Cheers!
Hi, can you give an example of how you're using the hook? i.e.:
@hook(AFTER_SAVE, has_changed=True)
This doesn't happen if is_changed=False but if True then every field in the model is checked for changes.
This is the expected behaviour
class Player(LifecycleModelMixin, AbstractUser):
name_embedding = VectorField(dimensions=1536, blank=True, null=True)
# has_changed=False at the moment because of bug with VectorField
@hook(AFTER_CREATE)
@hook(AFTER_SAVE, when_any=["username", "first_name", "last_name"])
def update_name_embedding(self):
...
This doesn't happen if is_changed=False but if True then every field in the model is checked for changes.
This is the expected behaviour
I can see that could make sense, but it's ambiguous when using when_any
.
Perhaps it would be better if has_changed
could accept a boolean (checks all fields) or a string or list of strings (checks only these fields)?
I'm sorry but I'm not sure if I understand what you want to achieve. Could you write in words when you expect your hooks to be fired so I can help you better?
I have firstname, last name username fields on the Player model (a User subclass).
I use these to create a text embedding of a combined string f"{firstname} {last_name} {username}.
This is used by a semantic search engine to match usernames in unstructured user-generated data.
I have a function that calls the OpenAI API to generate the embedding. I want this to be called:
- When a player is added (AFTER_CREATE)
- When any of the 3 fields mentioned above are changed (AFTER_SAVE, when_any=["username", "first_name", "last_name"])
I don't want it to be called if other fields on the Player model change, so would like the has_changed flag to apply only to the fields mentioned in the AFTER_SAVE decorator.
so would like the has_changed flag to apply only to the fields mentioned in the AFTER_SAVE decorator.
That's how it works.
This should do the trick, it will fire the hook when any of these changes.
@hook(AFTER_SAVE, when_any=["username", "first_name", "last_name"], has_changed=True)
class Player(LifecycleModelMixin, AbstractUser):
name_embedding = VectorField(dimensions=1536, blank=True, null=True)
@hook(AFTER_CREATE)
@hook(AFTER_SAVE, when_any=["username", "first_name", "last_name"], has_changed=True)
def update_name_embedding(self):
...