Was ich tun möchte, ist schreiben Code, mit dem ich Django-Objektinstanzen aus einer CSV-Datei laden kann. Offensichtlich sollte ich zuerst alle Daten überprüfen, bevor ich etwas speichere.Django Modell Instanz full_clean Methode, ist das richtig?
tl; dr: Die Methode full_clean() fängt keinen bevorstehenden Versuch ein, None in einem Feld ohne null=True
zu speichern. Scheint pervers. Ist das Absicht, und wenn ja, warum? Django hat weniger Fehler als alles andere, mit dem ich je gearbeitet habe, also "Bug!" scheint sehr unwahrscheinlich.
Vollversion. Was ich dachte, würde funktionieren, ist für jede Zeile, erstellen Sie eine Objektinstanz, füllen Sie Felder mit den Daten aus der Tabelle und rufen Sie dann die full_clean-Methode auf. I.e. (In Umrissen)
from django.core.exceptions import ValidationError
...
# upload a CSV file and open with a csvreader
errors=[]
for rownumber, row in enumerate(csvreader):
o = SomeDjangoModel()
o.somefield = row[0] # repeated for all input data row[1] ...
try:
reason = ""
o.full_clean()
except ValidationError as e:
reason = "Row:{} Reason:{}".format(rownumber, str(e))
errors.append(reason)
# reason, together with the row-number of the csv file, fully explains
# what is wrong.
# end of loop
if errors:
# display errors to the user for him to fix
else:
# repeat the loop, doing .save() instead of .full_clean()
# and get database integrity errors trying to save Null in non-null model field.
Das Problem ist, ist .full_clean()
nicht Keine Werte in Feldern fangen ohne null=True
Was soll ich tun? Ideen sind
das Ganze in einer Transaktion wickeln, eine Charge von o.save() innerhalb einer Exception-Handler tun, und rollen Sie die gesamte Transaktion zurück, es sei denn keine Fehler aufgetreten sind. Aber warum sollte die Datenbank gestört werden, wenn wahrscheinlich 90% der Versuche auf triviale Weise ausbrechen?
Fügen Sie die Daten über ein Formular ein, obwohl keine Interaktionen auf Formularebene pro Zeile mit dem Benutzer vorhanden sind.
Manuell auf Keine prüfen, wo es nicht sein sollte. Aber was macht .full_clean nicht?
kann ich verstehen, dass letztlich die einzige Möglichkeit, die Integrität der Datenbank Fehler abzufangen, um zu versuchen, die Daten zu speichern, aber warum Django nicht allein fängt keine in einem Null = False Feld?
BTW Dieses Django 1.9.6
hinzugefügt Detail. Dies ist relevant Felder der Modelldefinition
class OrderHistory(models.Model):
invoice_no = models.CharField(max_length=10, unique=True) # no default
invoice_val= models.DecimalField(max_digits=8, decimal_places=2) # no default
date = models.DateField() # no default
und das ist, was aus python manage.py shell
, getan geschieht, zu zeigen, dass die .full_clean Methode ein
>>> from orderhistory.models import OrderHistory
>>> from datetime import date
>>> o = OrderHistory(date=date(2010,3,17), invoice_no="21003163")
>>> o.invoice_val=None
>>> o.full_clean() # passes clean
>>> o.save() # attempt to save this one which has passed full_clean() validation
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/nigel/.virtualenvs/edge22/lib/python3.4/site-packages/django/db/models/base.py", line 708, in save
force_update=force_update, update_fields=update_fields)
File "/home/nigel/.virtualenvs/edge22/lib/python3.4/site-packages/django/db/models/base.py", line 736, in save_base
updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
File "/home/nigel/.virtualenvs/edge22/lib/python3.4/site-packages/django/db/models/base.py", line 820, in _save_table
result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "/home/nigel/.virtualenvs/edge22/lib/python3.4/site-packages/django/db/models/base.py", line 859, in _do_insert
using=using, raw=raw)
File "/home/nigel/.virtualenvs/edge22/lib/python3.4/site-packages/django/db/models/manager.py", line 122, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/nigel/.virtualenvs/edge22/lib/python3.4/site-packages/django/db/models/query.py", line 1039, in _insert
return query.get_compiler(using=using).execute_sql(return_id)
File "/home/nigel/.virtualenvs/edge22/lib/python3.4/site-packages/django/db/models/sql/compiler.py", line 1060, in execute_sql
cursor.execute(sql, params)
File "/home/nigel/.virtualenvs/edge22/lib/python3.4/site-packages/django/db/backends/utils.py", line 79, in execute
return super(CursorDebugWrapper, self).execute(sql, params)
File "/home/nigel/.virtualenvs/edge22/lib/python3.4/site-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "/home/nigel/.virtualenvs/edge22/lib/python3.4/site-packages/django/db/utils.py", line 95, in __exit__
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/home/nigel/.virtualenvs/edge22/lib/python3.4/site-packages/django/utils/six.py", line 685, in reraise
raise value.with_traceback(tb)
File "/home/nigel/.virtualenvs/edge22/lib/python3.4/site-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
django.db.utils.IntegrityError: null value in column "invoice_val" violates not-null constraint
DETAIL: Failing row contains (2, 21003163, , , 2010-03-17, , null, null, null, null, null, null).
>>>
>>> p = OrderHistory(invoice_no="21003164") # no date
>>> p.date=None
>>> p.full_clean() # this DOES error as it should
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/nigel/.virtualenvs/edge22/lib/python3.4/site-packages/django/db/models/base.py", line 1144, in full_clean
raise ValidationError(errors)
django.core.exceptions.ValidationError: {'date': ['This field cannot be null.']}
>>>
Wie werden None-Werte in Ihrer CSV-Datei dargestellt? Sie haben einen Fehler beim Einrücken des Codes, siehe letzte 4 Zeilen, wo Sie nach Fehlern suchen und speichern. – ozren1983
Das ist kein Codefehler. Ich sammle Fehler während der Schleife. Nach der Schleife, wenn es Fehler gab, zeige ich alle an, andernfalls wiederhole ich die Schleife, die save() anstelle von full_clean() vornimmt. (Dies könnte zu Datenbankintegritätsfehlern führen, aber das ist für diese Frage nicht relevant). – nigel222
Null in CSV-Datei ist zwei Kommas mit nichts zwischen ihnen. Ich behandle auch eine Whitespace-Zeichenfolge in einer numerischen Spalte als null (es ist ein Benutzer, der die Daten spreizt, anstatt sie zu löschen, ein übliches Anti-Pattern für Tabellenkalkulationen). – nigel222