Django: Инициализация FormSet пользовательских форм с экземплярами
Учитывая следующие модели:
class Graph(models.Model):
owner = models.ForeignKey(User)
def __unicode__(self):
return u'%d' % self.id
class Point(models.Model):
graph = models.ForeignKey(Graph)
date = models.DateField(primary_key = True)
abs = models.FloatField(null = True)
avg = models.FloatField(null = True)
def __unicode__(self):
return u'%s' % self.date
Я пытаюсь создать форму для редактирования списков Points.
Теги ввода HTML требуют установки дополнительных атрибутов, поэтому я использую следующую настраиваемую форму:
class PointForm(forms.ModelForm):
graph = forms.ModelChoiceField(queryset = Graph.objects.all(),
widget = forms.HiddenInput())
date = forms.DateField(widget = forms.HiddenInput(), label = 'date')
abs = forms.FloatField(widget = forms.TextInput(
attrs = {'class': 'abs-field'}),
required = False)
class Meta:
model = Point
fields = ('graph', 'date', 'abs') # Other fields are not edited.
def pretty_date(self):
return self.data.strftime('%B')
В этот момент я не знаю, как передать экземпляры класса Point в FormSet:
def edit(request):
PointFormSet = forms.formsets.formset_factory(PointForm, extra = 0)
if request.method == 'POST':
return
# Receive 3 points to edit from the database.
graph, res = Graph.objects.get_or_create(id = 1)
one_day = datetime.timedelta(days = 1)
today = datetime.date.today()
do_edit = []
for date in [today - (x * one_day) for x in range(3)]:
point, res = Point.objects.get_or_create(graph = graph, date = date)
do_edit.append(point)
formset = PointFormSet(????) # How is this initialized with the points?
Я нашел хак, который несколько работает, но впоследствии он приводит к ошибкам при попытке обработать результирующие данные POST:
do_edit = []
for date in [today - (x * one_day) for x in range(3)]:
point, res = Point.objects.get_or_create(graph = graph, date = date)
data = point.__dict__.copy()
data['graph'] = graph
do_edit.append(data)
formset = PointFormSet(initial = do_edit)
Как это делается правильно?
Для справки мой шаблон выглядит следующим образом:
<form action="" method="post">
{{ formset.management_form }}
<table>
<tbody>
{% for form in formset.forms %}
<tr>
<td>{{ form.graph }} {{ form.date }} {{ form.pretty_date }}:</td>
<td width="100%">{{ form.abs }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</form>
Ответы
Ответ 1
Хитрость заключается в использовании "ModelFormset" вместо простого набора форм, поскольку они позволяют инициализировать с помощью набора запросов. Документы здесь, то, что вы делаете, представляет собой форму = * при создании набора форм и queryset = * при создании экземпляра набора форм. Форма = * аргумент плохо документирован (пришлось немного копаться в коде, чтобы убедиться, что он на самом деле там).
def edit(request):
PointFormSet = modelformset_factory(Point, form = PointForm)
qset = Point.objects.all() #or however your getting your Points to modify
formset = PointFormset(queryset = qset)
if request.method == 'POST':
#deal with posting the data
formset = PointFormset(request.POST)
if formset.is_valid():
#if it is not valid then the "errors" will fall through and be returned
formset.save()
return #to your redirect
context_dict = {'formset':formset,
#other context info
}
return render_to_response('your_template.html', context_dict)
Таким образом, код легко проходит. Если запрос представляет собой GET, то пользовательская форма возвращается пользователю. Если запрос является POST, а форма not .is_valid()
, то ошибки "проваливаются" и возвращаются в одном шаблоне. Если запрос является POST и данные действительны, то набор форм сохраняется.
Надеюсь, что это поможет.
-Будет
Ответ 2
Если у вас есть только одно возможное значение, которое вы хотите установить, или, возможно, закрытое значение, можно установить их после того, как пользователь ПОЧТОВАЕТ данные на ваш сервер, используя commit=False
Обратите внимание на следующий код:
class UserReferralView(View):
ReferralFormSet = modelformset_factory(ReferralCode,
form=ReferralTokenForm, extra=1)
def get(self, request):
pass
def post(self, request):
referral_formset = UserUpdateView.ReferralFormSet(request.POST)
if referral_formset.is_valid():
instances = referral_formset.save(commit=False)
for instance in instances:
instance.user = request.user
instance.save()
return redirect(reverse('referrals.success_view'))
else:
return redirect(reverse('referrals.failure_view'))