Django CreateView- ModelForm с множеством InlineFormset ValueError - PullRequest
0 голосов
/ 04 декабря 2018

Я борюсь с такой проблемой:

У меня есть модели:

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.

Проблема, вероятно, заключается в коммите = False в методе form_valid, но я понятия не имею, какотремонтировать его.

Кто-нибудь знает, как решить эту проблему?Спасибо.

1 Ответ

0 голосов
/ 04 декабря 2018

Хорошо, я думаю, что здесь есть пара проблем, как в ваших post, так и form_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).Там происходит то, что вы «притворяетесь», что спасаете родителя, а затем пытаетесь полностью спасти детей.В базе данных нет записи о родителе, поэтому она выдает эту ошибку.Обязательное выполнение перед сохранением множества записей - по крайней мере, по моему опыту).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...