diff options
author | Magnus Hagander | 2024-01-21 14:09:31 +0000 |
---|---|---|
committer | Magnus Hagander | 2024-01-21 14:09:31 +0000 |
commit | 04d3df3547a2bf04b819590a9cf7a6e7ce6f0919 (patch) | |
tree | 8cb800a245674b7d2e54b7dd66e8365e88de41bd /postgresqleu/util/backendviews.py | |
parent | 15e0e750d7d4d019cd628b1accf270cf74ed4822 (diff) |
Handle database level constraint errors in backend editor
Backend editor would just crash if we failed to save due to a database
level constraint (foreign key, unique etc), even if said constraint was
defined in django (not for foreign keys as they drive dropdowns, but
django does not validate uniqueness, and there could always be a CHECK
constraint as well). So trap any such exceptions when trying to save and
just show the full error message to the user, instead of crashing.
Diffstat (limited to 'postgresqleu/util/backendviews.py')
-rw-r--r-- | postgresqleu/util/backendviews.py | 61 |
1 files changed, 32 insertions, 29 deletions
diff --git a/postgresqleu/util/backendviews.py b/postgresqleu/util/backendviews.py index 0ab40dd5..72836633 100644 --- a/postgresqleu/util/backendviews.py +++ b/postgresqleu/util/backendviews.py @@ -1,5 +1,5 @@ from django.core.exceptions import PermissionDenied, ValidationError -from django.db import transaction +from django.db import transaction, DatabaseError from django import forms from django.shortcuts import render, get_object_or_404 from django.urls import reverse, NoReverseMatch @@ -165,34 +165,37 @@ def backend_process_form(request, urlname, formclass, id, cancel_url='../', save # fields on the model, including those we don't care about. # The savem2m model, however, *does* care about the listed fields. # Consistency is overrated! - with transaction.atomic(): - if allow_new and ((not instance.pk) or form.force_insert): - form.pre_create_item() - form.save() - form._save_m2m() - all_excludes = ['_validator', '_newformdata'] + list(form.readonly_fields) + form.nosave_fields - if form.json_form_fields: - for fn, ffields in form.json_form_fields.items(): - all_excludes.extend(ffields) - - form.instance.save(update_fields=[f for f in form.fields.keys() if f not in all_excludes and not isinstance(form[f].field, forms.ModelMultipleChoiceField)] + form.extra_update_fields) - - # Merge fields stored in json - if form.json_form_fields: - for fn, ffields in form.json_form_fields.items(): - d = getattr(form.instance, fn, {}) - for fld in ffields: - if form.cleaned_data[fld] or not getattr(form.fields[fld], 'delete_on_empty', False): - # If we have a value, or if we're asked to store empty strings, - # then do so. - d[fld] = form.cleaned_data[fld] - elif form.cleaned_data[fld] == '' and getattr(form.fields[fld], 'delete_on_empty', False) and fld in d: - del d[fld] - setattr(form.instance, fn, d) - form.instance.save(update_fields=form.json_form_fields.keys()) - - form.post_save() - return HttpResponseRedirect(saved_url) + try: + with transaction.atomic(): + if allow_new and ((not instance.pk) or form.force_insert): + form.pre_create_item() + form.save() + form._save_m2m() + all_excludes = ['_validator', '_newformdata'] + list(form.readonly_fields) + form.nosave_fields + if form.json_form_fields: + for fn, ffields in form.json_form_fields.items(): + all_excludes.extend(ffields) + + form.instance.save(update_fields=[f for f in form.fields.keys() if f not in all_excludes and not isinstance(form[f].field, forms.ModelMultipleChoiceField)] + form.extra_update_fields) + + # Merge fields stored in json + if form.json_form_fields: + for fn, ffields in form.json_form_fields.items(): + d = getattr(form.instance, fn, {}) + for fld in ffields: + if form.cleaned_data[fld] or not getattr(form.fields[fld], 'delete_on_empty', False): + # If we have a value, or if we're asked to store empty strings, + # then do so. + d[fld] = form.cleaned_data[fld] + elif form.cleaned_data[fld] == '' and getattr(form.fields[fld], 'delete_on_empty', False) and fld in d: + del d[fld] + setattr(form.instance, fn, d) + form.instance.save(update_fields=form.json_form_fields.keys()) + + form.post_save() + return HttpResponseRedirect(saved_url) + except DatabaseError as e: + form.add_error(None, "Failed to save entry: {}".format(e)) else: form = formclass(request, conference, instance=instance, newformdata=newformdata) |