Closed orf closed 8 years ago
Hello,
Thanks for reporting. May I ask which release of which packages you updated? It might help getting a better grasp of why it stopped working.
Could you also post the part of the model that causes this issue? From the trace, it looks like audit_logs
appears as a translated field, which should not normally happen. I'm a bit confused and I might have to build a small model that shows the same error.
My apologies, the original report was slightly wrong/misleading. We have a requirement to have an audit log for each translated model, so I added the following class (the QAMixin
is also needed for compatibility with django-fsm
, which does some funky stuff):
class QATranslatedFields(TranslatedFields):
def _scan_model_bases(self, model):
bases, fields = super()._scan_model_bases(model)
bases = [QAMixin, AuditMixin] + bases
return bases, fields
The abstract AuditMixin
has the audit_logs = GenericRelation(AuditLog)
field, which gets included on the translated model. This worked fine in the previous release but is broken in the current one.
Obviously this isn't something you supported directly, but it did function perfectly. If you would like I can try and whip up a merge request to support this, but I'm not too sure where to start (other than perhaps filtering out any m2m
/generic
fields in the update_translation
function?)
If this isn't a use case you want to support then that's fine, I can modify our code to not do it this way.
Ok, I now understand how it gets there. So, this means, in your audit log, you have entries that actually point at a specific translation instead of the generic model.
This is indeed something that's not supported, because the main concept of hvad
is it does not actually appear in the database schema, but acts as a drop-in replacement for field values. It supports a “display language”, which has no explicity identity. This is the reason creating foreign keys to the translations model is not supported, and the translations model is mostly hidden as an implementation detail.
Now, it is true that when you use hvad in a project and you have a single instance where you want to interact with translations, it can make sense to “misuse” hvad a bit. Usually, when possible, I would recommend doing that by:
AuditMixin
on the main model)language_code
field to the audit entries.This does have the drawback of requiring the audit model to be aware of the language. I understand how this can be problematic in some cases.
Anyway, I traced your issue, it comes from the optimizations that were added in the latest version of hvad:
update_fields
parameter is now supported in TranslatableModel.save
. It used to be just passed around for django
to handle it, but now hvad
can detect when only translated or only untranslated fields are being saved, and avoid updating the two tables when that happens.update_fields
when it updates translations.This dramatically cuts down on the number of SQL requests: before, if you updated 5 translations in a DRF serializer, 10 SQL requests were sent (the untranslatable fields were updated 5 times). Now, only 6 requests are sent (1 for untranslatable fields and 1 per translation).
As translation models cannot normally have m2m fields, the update_translation
method does not filter them out. Thus your problem. Should not be too hard to fix, and will improve compatibility with some of the edge case hvad is put to use in. It needs to update all fields, but only pass regular fields to update_fields
.
A proper fix will require building a sample testcase with failing test, which might actually be trickier than the fix itself. I cannot do it right now, but I should be able to spend some time on this in the weekend.
Thanks for the great reply, I'll re-factor the AuditLog to have a language code and stop abusing hvad like this :)
If you can do so, then definitely do. That will be much less trouble in the long run.
I still built a fix for this specific issue, so it should be gone on master
.
I think this distinction of language as in “translating some field values” and language as in “semantically meaningful part of the database schema” should go in the FAQ, as it's commonly overlooked, but has strong implications. I'll add that next time I update it.
Thanks for taking the time to report your issue :)
Hey, We are using
hvad
with DRF and it's amazing, thanks for the library and your time in making it.We've run into a small issue when updating to the new release. One of our models has a
GenericRelation
to anAuditLog
model:audit_logs = GenericRelation(AuditLog)
, and with the new release it triggers the following error when saving:As far as I can tell the problem lies within the
update_translation
method inrestframework/serializers.py
:This returns
audit_logs
in the list, but I think it should be excluded, as it's not an actual field on the model that can be updated.