2013-11-15 17 views
7

背景:私のDjangoアプリケーションは、既存のPostgresqlデータベースの最上位に位置しています。このデータベースにはトリガーと制約の非常に複雑なネットワークがあります。Django管理者のデータベースエラーを表示する方法

質問:Django Adminでは、ユーザーが保存時にDatabaseErrorを発生させた場合、エラーを組み込みのforms.ValidationErrorに似た使いやすい形式で戻したいと思います。

例は

def save_model(self, request, obj, form, change): 
    try: 
     obj.save() 
    except DatabaseError as e: 
     raise forms.ValidationError(e) 

予想される結果(これは動作しません、それは500原因): "Database Error: ID 58574 - Price is outside customers requested range. Cannot add or update a child row: a foreign key constraint fails"

、管理者にユーザーに表示します

+0

'価格は、外部顧客が要求range'です:あなたは、私はすべてのモデルのために働くより汎用的な何かを探していたモデル(とあなたが指定した制約) – karthikr

+0

を表示することができます/制約。 – keithhackbarth

答えて

4

@twil - ご協力いただきありがとうございます。あなたは私を正しい軌道に乗せる。本当に助けに感謝します。しかし、その解決策は納得できませんでした。実際にテストケースにエラーを表示したり、change_viewで作業したりしていませんでした。ここで私は仕事をしたかったです。

from django.contrib.admin import ModelAdmin 
from django.db import DatabaseError, IntegrityError 
from django.contrib import messages 


class ShowValidationAdmin(ModelAdmin): 

    def add_view(self, request, form_url='', extra_context=None): 
     try: 
      return super(ShowValidationAdmin, self).add_view(request, form_url, extra_context) 
     except (IntegrityError, DatabaseError) as e: 

      request.method = 'GET' 
      messages.error(request, e.message) 
      return super(ShowValidationAdmin, self).add_view(request, form_url, extra_context) 

    def change_view(self, request, object_id, form_url='', extra_context=None): 
     try: 
      return super(ShowValidationAdmin, self).change_view(request, object_id, form_url, extra_context) 
     except (IntegrityError, DatabaseError) as e: 

      request.method = 'GET' 
      messages.error(request, e.message) 
      return super(ShowValidationAdmin, self).change_view(request, object_id, form_url, extra_context) 

注:このバージョンはクロスバージョン(django 1.3-1.6)でも動作するようです。誰かがより良いアプローチをしているかどうかを教えてください。私は賞金を授与するのを待つつもりです。

+2

あなたの解決方法は、 'request.method = 'GET'で変更を失っているので、短くて使い勝手が悪いです。ユーザーは必要なフィールドをすべて補充し、間違ったフィールドだけを修正する必要があります。 – twil

5

可能であれば、ロジックを少し変更する必要があります。必要なのは、カスタムAdminModel.formです。すべてのバリデーションはそこで行われるべきです。 save_model()のための注意を参照してください:

ModelAdmin.save_model()とModelAdmin.delete_model()/セーブ オブジェクトを削除する必要があり、彼らは拒否権の目的ではなく、むしろ、彼らは にあなたが余分な操作を行うことができます。

しかし、あなたは私がModelAdminをサブクラス化し、オーバーライドしたいフォーム内のすべての検証を行うことができないように、あなたの事情がある場合def add_view()def change_view()def changelist_view()そうのような:

from django.contrib import admin 
from django import forms 
from django.contrib.admin import helpers 
from django.contrib.admin.options import csrf_protect_m, IS_POPUP_VAR 
from django.utils.translation import ugettext as _ 
from django.utils.encoding import force_text 

# for nonfield errors to show correctly 
from django.forms.forms import NON_FIELD_ERRORS 

from .models import TestModel 


class TestModelAdmin(admin.ModelAdmin): 

    def save_model(self, request, obj, form, change): 

     raise Exception('test exception') 

    @csrf_protect_m 
    def add_view(self, request, form_url='', extra_context=None): 
     try: 
      return super(TestModelAdmin, self).add_view(request, form_url, extra_context) 
     except Exception as e: 
      pass 

     # mimic parent class on error 

     model = self.model 
     opts = model._meta 

     ModelForm = self.get_form(request) 
     formsets = [] 
     inline_instances = self.get_inline_instances(request, None) 
     form = ModelForm(request.POST, request.FILES) 
     form.is_valid() 

     # make faked nonfield error 
     # see http://stackoverflow.com/questions/8598247/how-to-append-error-message-to-form-non-field-errors-in-django 
     form._errors[NON_FIELD_ERRORS] = form.error_class([e.message]) 

     # We may handle exception here (just to save indentation) 
     adminForm = helpers.AdminForm(form, list(self.get_fieldsets(request)), 
      self.get_prepopulated_fields(request), 
      self.get_readonly_fields(request), 
      model_admin=self) 
     media = self.media + adminForm.media 

     inline_admin_formsets = [] 
     for inline, formset in zip(inline_instances, formsets): 
      fieldsets = list(inline.get_fieldsets(request)) 
      readonly = list(inline.get_readonly_fields(request)) 
      prepopulated = dict(inline.get_prepopulated_fields(request)) 
      inline_admin_formset = helpers.InlineAdminFormSet(inline, formset, 
       fieldsets, prepopulated, readonly, model_admin=self) 
      inline_admin_formsets.append(inline_admin_formset) 
      media = media + inline_admin_formset.media 

     context = { 
      'title': _('Add %s') % force_text(opts.verbose_name), 
      'adminform': adminForm, 
      'is_popup': IS_POPUP_VAR in request.REQUEST, 
      'media': media, 
      'inline_admin_formsets': inline_admin_formsets, 
      'errors': helpers.AdminErrorList(form, formsets), 
      'app_label': opts.app_label, 
      'preserved_filters': self.get_preserved_filters(request), 
     } 
     context.update(extra_context or {}) 
     return self.render_change_form(request, context, form_url=form_url, add=True) 

admin.site.register(TestModel, TestModelAdmin) 

マイmodels.py

from django.db import models 

class TestModel(models.Model): 

    text = models.TextField() 

save_model()の中に簡単にフックする方法はありませんので、パートをコピーして貼り付ける必要がありますフォーム準備コードの。

0

これを試してみてください:

from django.core.exceptions import ValidationError 
    def save_model(self, request, obj, form, change): 
     try: 
      obj.save() 
     except DatabaseError as e: 
      raise ValidationError(e) 
+0

私のアプリケーションで500エラーが投げられました。 – d33tah

関連する問題