Я пытаюсь использовать inlineformset_factory для генерации formset. Мои модели определяются как:
class Measurement(models.Model):
subject = models.ForeignKey(Subject)
experiment = models.ForeignKey(Experiment)
assay = models.ForeignKey(Assay)
values = models.CommaSeparatedIntegerField(blank=True, null=True)
class Experiment(models.Model):
date = models.DateField()
notes = models.TextField(max_length = 500, blank=True)
subjects= models.ManyToManyField(Subject)
по моему мнению, я имею:
def add_measurement(request, experiment_id):
experiment = get_object_or_404(Experiment, pk=experiment_id)
MeasurementFormSet = inlineformset_factory(Experiment, Measurement, extra=10, exclude=('experiment'))
if request.method == 'POST':
formset = MeasurementFormSet(request.POST,instance=experiment)
if formset.is_valid():
formset.save()
return HttpResponseRedirect( experiment.get_absolute_url() )
else:
formset = MeasurementFormSet(instance=experiment)
return render_to_response("data_entry_form.html", {"formset": formset, "experiment": experiment }, context_instance=RequestContext(request))
но я хочу ограничить поле Measurement.subject только предметами, определенными в Experiment.subjects queryset. Я попробовал несколько различных способов сделать это, но я немного не уверен, каково лучший способ выполнить это. Я пытался переопределить класс BaseInlineFormset с новым queryset, но не мог выяснить, как правильно передать параметр эксперимента.
Обновленный ответ (я также включал информацию отсюда как способ передать параметр ссылке formset):
views.py
def add_measurement(request, experiment_id):
experiment = get_object_or_404(Experiment, pk=experiment_id)
MeasurementFormSet = inlineformset_factory(Experiment, Measurement, extra=10, can_delete=True, form=MeasurementForm)
MeasurementFormSet.form = staticmethod(curry(MeasurementForm, experiment=experiment))
if request.method == 'POST':
formset = MeasurementFormSet(request.POST)
if formset.is_valid():
formset.save()
return HttpResponseRedirect( experiment.get_absolute_url() )
else:
formset = MeasurementFormSet()
return render_to_response("data_entry_form.html", {"formset": formset, "experiment": experiment }, context_instance=RequestContext(request))
forms.py
class MeasurementForm(ModelForm):
class Meta:
model = Measurement
def __init__(self, *args, **kwargs):
experiment = kwargs.pop('experiment')
super(MeasurementForm, self).__init__(*args, **kwargs)
self.fields["subject"].queryset = Subject.objects.filter(experiment=experiment)
(редактировать: кодовые блоки неправильно прочитаны, здесь должно быть решение вашей проблемы):
Я считаю, что вам нужно: http://docs.djangoproject.com/en/dev/ref/ forms / fields / # modelchoicefield
Forms.py:
class MeasurementForm(ModelForm):
subject = forms.ModelChoiceField(queryset = Expirement.objects.all())
class Meta:
model = Measurement
Views.py:
inlineformset_factory(
Experiment, Measurement, extra=10,
exclude=('experiment'), form=MeasurementForm
)
Привязка к набору форм выполняется с помощью параметра формы.
У меня была такая же проблема (инициализация inlineforms с ограниченным количеством возможных значений), и обновленный ответ работает отлично. Спасибо за это. В любом случае, есть кое-что, что можно было бы сделать лучше, но я не знаю, как это сделать. Новая проблема в этом решении заключается в том, что вы бьете по базе данных в каждой инлайн-форме: вместо того, чтобы использовать один и тот же queryset во всех одинаковых полях, каждый раз пересчитывает его в этой строке:
self.fields["subject"].queryset = Subject.objects.filter(experiment=experiment)
Прав ли я в этом вопросе или здесь есть какая-то ленивая django-магия за капотом? Если я прав, то как я могу избежать (возможных сотен) обращений к БД? Приветствую, Pedro