3

私は次のモデルを持っています:

class Project(models.Model):
    title = models.CharField(max_length="100")

    pub_date = models.DateField(auto_now_add=True, editable=False)

    budget = models.IntegerField()

class Milestone(models.Model):

    title = models.CharField(max_length="50")

    budget_percentage = models.IntegerField(max_length=2)

    project = models.ForeignKey(Project)

プロジェクトの作成フォームに、マイルストーン用のインライン フォームセットを含めました。

プロジェクトが提出されたときに、少なくとも 4 つのマイルストーンが作成され、すべてのマイルストーンの Budget_percentage の合計が 100 になることを検証したい

これは私のフォームです:

class BaseMilestoneProjectFormSet(BaseFormSet):
    def clean(self):

        if any(self.errors):
            # Don't bother validating the forms unless each form is valid on its own
            return

        if len(self.forms) < REQUIRED_MILESTONES:
            raise forms.ValidationError("At least %s milestones need to be created" % REQUIRED_MILESTONES)

        # Set initial control variables
        # Total percentage of budget to control
        total_percentage = 0
        # Date to control that milestones are linear, i.e. that second milestone isn't delivered before first
        current_control_date = date.min

        for i, form in zip(range(len(self.forms)), self.forms):

            if i == 0 and form.budget_percentage > MAX_BUDGET_FIRST_MILESTONE:
                raise forms.ValidationError("First milestone budget must not exceed %s percentage" % MAX_BUDGET_FIRST_MILESTONE)
            elif form.budget_percentage > MAX_BUDGET_MILESTONE:
                raise forms.ValidationError("Milestone's budget must not exceed %s percentage" % MAX_BUDGET_MILESTONE)

            if form.estimated_delivery_date < current_control_date:
                raise forms.ValidationError("Milestones must be linear, check your delivery dates")

            # Set control variables for next iteration    
            current_control_date = form.estimated_delivery_date                
            total_percentage += form.budget_percentage

        if total_percentage != 100:
            raise forms.ValidationError("All milestones budget percentage should sum up to 100%")

3 つの空のマイルストーン フォームを含むフォームを送信すると、最初のフォームについては何もしません。ValidationError(...)

raise Exception() で実際に if に入ることを確認しましたが、何も起こらないかのように続行します。

それは私のコードのエラーですか、それとも ValidationError の誤解された概念ですか?

事前に感謝します。

編集:

欠落していたビューコードを追加しています

class DelayedModelFormMixin(ModelFormMixin):
    def form_valid(self, form):
        self.object = form.save(commit=False)
        self.prepare_object_for_save(self.object)
        self.object.save()
        if hasattr(self.object, "save_m2m"):
            self.object.save_m2m()
        return super(ModelFormMixin, self).form_valid(form)

    def prepare_object_for_save(self, obj):
        pass

class ProjectNew(CreateView, DelayedModelFormMixin):
    model = Project
    success_url = '/projects/project/%(slug)s'
    form_class = ProjectForm

    @method_decorator(login_required)
    def dispatch(self, request, *args, **kwargs):
        return super(ProjectNew, self).dispatch(request, *args, **kwargs)

    def prepare_object_for_save(self, obj):
        obj.owner = self.request.user
        # Code for stacked milestones and rewards
        context = self.get_context_data()
        milestone_form = context['milestone_formset']
        reward_form = context['reward_formset']
        if milestone_form.is_valid() and reward_form.is_valid():
            self.object = form.save()
            milestone_form.instance = self.object
            milestone_form.save()
            reward_form.instance = self.object
            reward_form.save()
            return HttpResponseRedirect(success_url)

    def form_invalid(self, form):
        return self.render_to_response(self.get_context_data(form=form))

    def get_context_data(self, **kwargs):
        context = super(ProjectNew, self).get_context_data(**kwargs)
        if self.request.POST:
            context['milestone_formset'] = MilestoneFormSet(self.request.POST)
            context['reward_formset'] = RewardFormSet(self.request.POST)
        else:
            context['milestone_formset'] = MilestoneFormSet()
            context['reward_formset'] = RewardFormSet()
        return context
4

1 に答える 1

0

私があなたの質問を理解している場合、問題は、フォームセット内にあるフォームの数を数えているが、フォームセット内にあるBOUNDフォームの数を数えたい/必要があるということです。

したがって、この行を変更する必要があると思います:

if len(self.forms) < REQUIRED_MILESTONES:

これらの行について:

bounded_forms = filter(lambda form:form.isbound(), self.forms)
if len(bounded_forms) < REQUIRED_MILESTONES:

その後、実行中に検証エラーを発生させることができます。

編集:

フォームセットの検証がどのように機能するかを理解していない可能性があります。これは、特に次のフレーズが役立つ場合があります。

formset clean メソッドは、すべての Form.clean メソッドが呼び出された後に呼び出されます。エラーは、フォームセットで non_form_errors() メソッドを使用して検出されます。

あなたの言っている意味が理解できれば

3 つの空のマイルストーン フォームを含むフォームを送信すると、最初のフォームについては何もしません。ValidationError(...)

その後、発生したエラーは表示されません。したがって、それらを探す場所はフォームセットの「non_form_errors」メソッドです。テンプレートに次のようなものを入れます。

<span>{{milestone_formset.non_form_errors}}</span>

これで、milestone formset clean メソッドで発生しているエラーが表示されるはずです。

それが役に立てば幸い!

于 2012-06-03T15:52:21.840 に答える