【问题标题】:Django CreateView- ModelForm with many-to-many InlineFormset ValueError带有多对多 InlineFormset ValueError 的 Django CreateView-ModelForm
【发布时间】:2019-05-06 06:02:37
【问题描述】:

我正在努力解决这样的问题:

我有模型:

class ForecastType(models.Model):
    client = models.ForeignKey(Client, related_name="weatherforecast_client")

    created_by = models.ForeignKey(Forecaster, related_name="weatherforecast_created_by")
    modified_by = models.ForeignKey(Forecaster,
                                    related_name="weatherforecast_modified_by",
                                    blank=True,
                                    null=True)

    creation_date = models.DateTimeField(auto_now_add=True)
    modification_date = models.DateTimeField(auto_now=True)

    weather_forecasts = models.ManyToManyField('WeatherForecast')

    STATUS_CHOICES = (
        ("D", "Draft"),
        ("A", "Active"),
        ("H", "History"),
    )
    status = models.CharField(max_length=1, choices=STATUS_CHOICES, default="D")


class OneDayForecast(ForecastType):
    def __str__(self):
        return f"Prognoza pogody dla: {self.client}, wykonana dnia: {self.creation_date}"


class WeatherForecast(models.Model):
    begin_date = models.DateTimeField(blank=True, null=True)
    finish_date = models.DateTimeField(blank=True, null=True)
    forecast_type = models.ForeignKey('ForecastType', null=True, blank=True)
    description = models.TextField(max_length=300, blank=True, null=True)

我也有 ModelForm 和 InlineFormset:

class OneDayForecastForm(ModelForm):
    class Meta:
        model = OneDayForecast
        exclude = ('weather_forecasts',)

WeatherForecastFormset = inlineformset_factory(OneDayForecast, WeatherForecast, exclude=('forecast_type',), extra=2)

最后是 CreateView:

class OneDayForecast(ForecasterRequiredMixin, CreateView):
    template_name = "forecaster/one_day.html"
    success_url = reverse_lazy("forecaster:dashboard")
    model = OneDayForecast
    form_class = OneDayForecastForm

    def get(self, request, *args, **kwargs):
        self.object = None
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        weather_forecast_form = WeatherForecastFormset()
        return self.render_to_response(
            self.get_context_data(form=form, weather_forecast_form=weather_forecast_form)
        )

    def post(self, request, *args, **kwargs):
        self.object = None
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        weather_forecast_form = WeatherForecastFormset(self.request.POST)
        if form.is_valid() and weather_forecast_form.is_valid():
            return self.form_valid(form, weather_forecast_form)
        else:
            return self.form_invalid(form, weather_forecast_form)

    def form_valid(self, form, weather_forecast_form):
        self.object = form.save(commit=False)

        for weather_form in weather_forecast_form:
            weather_object = weather_form.save()
            self.object.weatherforecast_set.add(weather_object)

        self.object.save()
        form.save_m2m()

        return HttpResponseRedirect(self.get_success_url())

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

尝试使用 InlineFormset 提交我的表单后,我收到此错误:

Request Method: POST
Request URL:    http://localhost:8000/forecaster/my-clients/6/one_day/
Django Version: 1.11
Exception Type: ValueError
Exception Value:    
Unsaved model instance <OneDayForecast: Forecast for: client1> cannot be used in an ORM query.

问题可能在于 form_valid 方法中的 commit=False 但我不知道如何修复它。

有人知道解决这个问题吗? 谢谢。

【问题讨论】:

    标签: django django-models django-forms django-orm inline-formset


    【解决方案1】:

    好的,所以我认为这里有几个问题,无论是在您的 postform_valid() 方法中。我参考了我自己的内联表单集实现,以了解您的不同之处。

    首先,我认为post方法的第一行应该是self.object = self.get_object()

    其次,weather_forecast_form = WeatherForecastFormset(self.request.POST) 应该是weather_forecast_form = WeatherForecastFormset(self.request.POST, instance=self.object)
    注意我们得到的对象之间的关系,然后在表单集中的实例中使用它。这就是 post 方法的全部内容。

    现在,在我自己的实现中,我有许多表单集,因此我按如下方式遍历每个表单集(如果将表单集放入列表并将其传递给form_valid,则可以使用完全相同的代码):

    def form_valid(self, form, formsets):
        self.object = form.save()
        for formset in formsets:
            formset.instance = self.object
            formset.save()
        return HttpResponseRedirect(self.get_success_url())
    

    请注意,我们在这里完全保存了父表单,包括提交它。然后我们保存所有表单集。如果你想保留你的单一表单集,你可以轻松地将上面的代码更改为以下代码:

    def form_valid(self, form, weather_forecast_form):
        self.object = form.save()
        weather_forecast_form.instance = self.object
        weather_forecast_form.save()
        return HttpResponseRedirect(self.get_success_url())
    

    您在问题底部报告的错误是form.save(commit=False) 的直接结果。那里发生的事情是你“假装”拯救父母,然后试图完全拯救孩子。数据库没有父母的记录,所以它吐出那个错误。在保存多对多记录之前提交是必须的(至少根据我的经验)。

    【讨论】:

      猜你喜欢
      • 2019-10-12
      • 2021-05-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-14
      • 2021-12-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多