Huh, for some reason I can't seem to get F working properly even on the simplest of models. Here on Django 1.9.x.
In the simplest form, TestAccount
class TestAccount(models.Model):
decimal = models.DecimalField(max_digits=5, decimal_places=2)
integer = models.IntegerField()
In [1]: ta = TestAccount()
In [2]: ta.integer = 1
In [3]: ta.decimal = 1
In [4]: ta.save()
In [5]:
In [5]:
In [5]: ta
Out[5]: <TestAccount: TestAccount object>
In [6]: ta.id
Out[6]: 1L
In [7]: from django.db.models.expressions import F
In [8]: ta = TestAccount.objects.get(id=1)
In [9]: ta.integer = F('integer') + 1
In [10]: ta.save()
---------------------------------------------------------------------------
ValidationError Traceback (most recent call last)
<ipython-input-10-6e9eda341b34> in <module>()
----> 1 ta.save()
/usr/lib/python2.7/site-packages/django/db/models/base.pyc in save(self, force_insert, force_update, using, update_fields)
706
707 self.save_base(using=using, force_insert=force_insert,
--> 708 force_update=force_update, update_fields=update_fields)
709 save.alters_data = True
710
/usr/lib/python2.7/site-packages/django/db/models/base.pyc in save_base(self, raw, force_insert, force_update, using, update_fields)
730 if not meta.auto_created:
731 signals.pre_save.send(sender=origin, instance=self, raw=raw, using=using,
--> 732 update_fields=update_fields)
733 with transaction.atomic(using=using, savepoint=False):
734 if not raw:
/usr/lib/python2.7/site-packages/django/dispatch/dispatcher.pyc in send(self, sender, **named)
190
191 for receiver in self._live_receivers(sender):
--> 192 response = receiver(signal=self, sender=sender, **named)
193 responses.append((receiver, response))
194 return responses
/media/sf_helium/build/helium/internal/signals.pyc in validate_model(sender, **kwargs)
12 def validate_model(sender, **kwargs):
13 if 'raw' in kwargs and not kwargs['raw']:
---> 14 kwargs['instance'].full_clean()
15
16 @receiver(pre_delete)
/usr/lib/python2.7/site-packages/django/db/models/base.pyc in full_clean(self, exclude, validate_unique)
1142
1143 if errors:
-> 1144 raise ValidationError(errors)
1145
1146 def clean_fields(self, exclude=None):
ValidationError: {'integer': [u"'F(integer) + Value(1)' value must be an integer."]}
But according to this: https://docs.djangoproject.com/en/1.9/ref/models/instances/#updating-attributes-based-on-existing-fields it should work...
Why F isn't being excluded from validation I don't know. It should be, and Django should just create a query to update it.
This works fine in pure Django. The problem in your case is that you have a listener (in helium.internal.signals
) to the pre_save
signal which tries to do this:
def validate_model(sender, **kwargs):
if 'raw' in kwargs and not kwargs['raw']:
kwargs['instance'].full_clean()
Model.full_clean
expects a bunch of values for each field in your model, but in this case one of your fields is not a value but a CombinedExpression
which hasn't yet been evaluated, and will only get evaluated when Django writes to the database. This causes the error.
IMO you either need to perform your own validation that implements the logic of full_clean
and handles Expression
s, or you need to exclude fields containing expressions from full_clean
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With