基本的に、環境上のアプリケーションにリンクされた DB に Alert オブジェクトを挿入する ModelForm を作成し、連絡先 (ForeignKey で管理) にメールを送信することができました。私のフォーム (CreateView クラスベースのフォームに基づく) は、3 つのフィールドで構成されています。
- アプリケーションの CharField
- 環境の ModelChoiceField
- 連絡先の EmailField
CreateView は、いくつかの AJAX ロジックと混合されて、送信を全体的に動的にします (つまり、フォームの上に大きなエラーを表示する代わりに、各フィールドの横にページをリロードせずにエラーのツールチップを描画します)。
ModelForm のロジックは次のとおりです。
- アプリケーションが DB に既に存在するかどうかを確認します。それ以外の場合は、ValidationError が発生します
- 連絡先メールアドレスがDBに存在するか確認してください。それ以外の場合は作成します
- 結果として作成される Alert オブジェクトが DB に既に存在するかどうかを確認します。存在する場合、ValidationError が発生します。
これまでのところ、存在しない連絡先メール アドレスでフォームを送信する場合を除いて、すべて正常に動作します。ModelForm で「このフィールドを null にすることはできません」という検証エラーが発生します。
必要に応じて ModelForm の clean_contact() メソッドで get_or_create() メソッドを使用してこの連絡先を挿入し、結果のオブジェクトを返して self.cleaned_data 辞書を更新するため、間違っていることは本当にわかりませんでした。最悪なのは、フィールドを変更せずにフォームをもう一度送信すると、すべてがスムーズに実行されることです(検証エラーはもうありません)...
データベースに既存のメールアドレスを使用してフォームを送信すると、最初のフォーム送信時にすべてが正常に機能します。
私のコードのどこが間違っているのか、POST されたすべてのデータが正しいのになぜこのエラーが発生するのかを指摘していただければ幸いです。
ただし、CreateView との AJAX ミックスインについては少し疑問があります。メール アドレスが不明な場合、get_or_create() が作成して返す可能性があるためです。しかし、理由は想像できませんが、Alert オブジェクトの作成新しく作成された連絡先オブジェクトをまだ参照できませんでした。これは、2 番目の送信が機能する理由を説明することができます...これに関する最終的な言葉を皆さんが理解できると確信しています :-)
前述の問題に関連するさまざまなアプリケーション部分の下。このアプリケーションで使用されていない一部のモデル フィールドと、CreateView から継承された LoginRequiredMixin を自発的に削除しました。
繰り返しますが、その点であなたの助けに本当に感謝しており、すべてのアドバイスに事前に感謝しています.
モデル
class UmsAlerting(models.Model):
alert_id = models.IntegerField(primary_key=True, editable=False)
appli = models.ForeignKey('UmsApplication')
env = models.ForeignKey('UmsEnvironment')
contact = models.ForeignKey('UmsContacts')
class Meta:
db_table = 'ums_alerting'
def __unicode__(self):
return u'Alert_Id %d on %s(%s)' %(self.alert_id, self.appli.trigram_ums, self.env.env_name)
class UmsApplication(models.Model):
appli_id = models.IntegerField(primary_key=True)
trigram_ums = models.CharField(max_length=4L)
class Meta:
db_table = 'ums_application'
class UmsContacts(models.Model):
contact_id = models.IntegerField(primary_key=True)
mail_addr = models.CharField(max_length=100L)
class Meta:
db_table = 'ums_contacts'
class UmsEnvironment(models.Model):
env_id = models.IntegerField(primary_key=True)
env_name = models.CharField(max_length=5L)
class Meta:
db_table = 'ums_environment'
def __unicode__(self):
return self.env_name
モデルフォーム
class AlertForm(ModelForm):
class Meta:
model = UmsAlerting
exclude = ('custom_rule')
appli = forms.CharField(required=True, max_length=3)
env = forms.ModelChoiceField(required=True,
queryset=UmsEnvironment.objects.all())
contact = forms.EmailField(required=True)
def clean_appli(self):
data = self.cleaned_data['appli']
try:
UmsApplication.objects.get(trigram_ums=data)
except ObjectDoesNotExist:
msg = 'Trigram must be known and valid.'
self._errors['appli'] = self.error_class([msg])
raise forms.ValidationError(msg)
return UmsApplication.objects.get(trigram_ums=data)
def clean_contact(self):
data = self.cleaned_data['contact']
c, created = UmsContacts.objects.get_or_create(mail_addr=data)
return c
def clean(self):
cleaned_data = super(AlertForm, self).clean()
app = cleaned_data.get('appli')
contact = cleaned_data.get('contact')
env = cleaned_data.get('env')
# Do not insert a new alert if it already exists
if UmsAlerting.objects.filter(appli=app, env=env, contact=contact).count() > 0:
msg = 'Alert is already configured.'
self._errors['contact'] = self.error_class([msg])
raise forms.ValidationError(msg)
# Return the parent's clean method finally
return cleaned_data
CreateView
class AlertView(LoginRequiredMixin, AjaxResponseMixin, CreateView):
template_name = 'tools/alert_form.html'
form_class = AlertForm
success_url = reverse_lazy('alerts_configure')
AjaxResponseMixin
class AjaxResponseMixin(object):
def render_to_json_response(self, context, **kwargs):
data = json.dumps(context)
kwargs['content_type'] = 'application/json'
return HttpResponse(data, **kwargs)
def form_invalid(self, form):
response = super(AjaxResponseMixin, self).form_invalid(form)
if self.request.is_ajax():
return self.render_to_json_response(form.errors, status=400)
else:
return response
# Not really useful actually (yet)
def form_valid(self, form):
response = super(AjaxResponseMixin, self).form_valid(form)
if self.request.is_ajax():
return self.render_to_json_response(json.dumps({}))
else:
return response