2016-06-26 16 views
5

Huh, z jakiegoś powodu wydaje mi się, że F nie działa poprawnie nawet w najprostszych modelach. Tutaj na Django 1.9.x.Django F nie działa?

W najprostszej formie, 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."]} 

Ale według tego: https://docs.djangoproject.com/en/1.9/ref/models/instances/#updating-attributes-based-on-existing-fields powinno działać ...

Dlaczego F nie jest wykluczony z walidacji nie wiem. Tak powinno być, a Django powinien po prostu utworzyć zapytanie, aby je zaktualizować.

Odpowiedz

5

Działa to dobrze w czystym Django. Problem w Twoim przypadku jest to, że masz słuchacza (w helium.internal.signals) do sygnału pre_save który stara się to zrobić:

def validate_model(sender, **kwargs): 
    if 'raw' in kwargs and not kwargs['raw']: 
     kwargs['instance'].full_clean() 

Model.full_clean oczekuje kilka wartości dla każdego pola w modelu, ale w tym przypadku jednego z twoich pól nie jest wartością, ale CombinedExpression, która nie została jeszcze oceniona, i zostanie oceniona tylko wtedy, gdy Django zapisuje do bazy danych. Powoduje to błąd.

IMO albo trzeba wykonać swoją walidacji, która implementuje logikę full_clean i uchwyty Expression S, albo trzeba wykluczyć pola zawierające wyrażeń z full_clean.