-
-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cannot use callable default property on model ForeignKeys #20
Comments
Hi @airguru, Yeah, the problem isn't about using a callable default property. It's because class definitions are loaded very early by Python. Therefore, with your field definition, Django tries to do a database query before everything is set up properly. Even though it's possible to do this, I don't think this is something that you should do 🤔 Funnily enough, have you tried wrapping the value in an actual callable? Something like: def default_system_currency():
return Currency.objects.first().code
class SomeModel(models.Model):
...
system_currency = models.ForeignKey(Currency, on_delete=models.PROTECT, to_field='code', default=default_system_currency)
... I think it should defer the query until it's actually needed. |
Yes, wrapping it actually works! I thought database queries are lazy enough to be deferred until actually needed! But either way, even if it's possibly not something that one should do, it's unfortunately possible (and suggested as an option for default foreign key values in some stackoverflow answers) and when it breaks it's quite hard to find the cause. Especially because you can't really make sense of anything in debug mode. The attribute that's supposed to be mising actually shows up when the debugger breaks on the exception (so maybe the Maybe the |
Model fields are created as Python class attributes. That means they get evaluated very early on by Python, not Django (correct me if I'm wrong here). When defining Calling Your initial guess,
is correct. I would've suggested moving the app to the top of Thankfully Django accepts a callable for
I guess we could do that by changing the direct attribute access ( If we only care about |
Whenever I use something like this in my model:
system_currency = models.ForeignKey(Currency, on_delete=models.PROTECT, to_field='code', default=Currency.objects.first().code)
I get
AttributeError: 'DatabaseFeatures' object has no attribute 'has_native_json_field'
when trying to query a model that contains JSONField. Surprisingly, it doesn't seem to affect admin interface.Changing the default property to constant value fixes the issue:
system_currency = models.ForeignKey(Currency, on_delete=models.PROTECT, to_field='code', default='eur')
It seems that maybe using queries inside model definitions somehow initializes the db config before this library can inject itself into it. Moving the library into the first place in
INSTALLED_APPS
doesn't help.Phew! Took me a while to figure this out!
The text was updated successfully, but these errors were encountered: