Django pasa parámetros de formulario personalizados a ModelFormset
-
06-07-2019 - |
Pregunta
Mi problema es similar a Django pasando parámetros de formulario personalizado al conjunto de formularios
Tengo estas clases
class Game(models.Model):
home_team = models.ForeignKey(Team, related_name='home_team')
away_team = models.ForeignKey(Team, related_name='away_team')
round = models.ForeignKey(Round)
TEAM_CHOICES = ((1, '1'), (2, 'X'), (3, '2'),)
class Odds(models.Model):
game = models.ForeignKey(Game, unique=False)
team = models.IntegerField(choices = TEAM_CHOICES)
odds = models.FloatField()
class Meta:
verbose_name_plural = "Odds"
unique_together = (
("game", "team"),
)
class Vote(models.Model):
user = models.ForeignKey(User, unique=False)
game = models.ForeignKey(Game)
score = models.ForeignKey(Odds)
class Meta:
unique_together = (
("game", "user"),)
Y he definido mi propio modelformset_factory:
def mymodelformset_factory(ins):
class VoteForm(forms.ModelForm):
score = forms.ModelChoiceField(queryset=Odds.objects.filter(game=ins), widget=forms.RadioSelect(), empty_label=None)
def __init__(self, *args, **kwargs):
super(VoteForm, self).__init__(*args, **kwargs)
class Meta:
model = Vote
exclude = ['user']
return VoteForm
Y lo uso así:
VoteFormSet = modelformset_factory(Vote, form=mymodelformset_factory(v), extra=0)
formset = VoteFormSet(request.POST, queryset=Vote.objects.filter(game__round=round, user=user))
Esto muestra el formulario:
cuadro desplegable de Juego (s) en la Ronda especificada y se supone que muestra 3 botones de radio para las Probabilidades, pero no sé qué pasar como parámetro a mymodelformset_factory .. If v = Game.objects. get (pk = 1) obviamente solo muestra Juego con pk = 1 para TODOS los juegos, lo que necesito es v = Game.objects.get (pk = " juego que está conectado a las probabilidades con respecto a ") si captas mi deriva ..
Solución
Creo que desea realizar algunos cambios en su función de fábrica personalizada. Debería devolver la clase de conjunto de formularios, no el formulario. ¿Qué tal esto?
def make_vote_formset(game_obj, extra=0):
class _VoteForm(forms.ModelForm):
score = forms.ModelChoiceField(
queryset=Odds.objects.filter(game=game_obj),
widget=forms.RadioSelect(),
empty_label=None)
class Meta:
model = Vote
exclude = ['user',]
return modelformset_factory(Vote, form=_VoteForm, extra=extra)
Luego, en su código de vista:
current_game = Game.objects.filter(id=current_game_id)
VoteFormSet = make_vote_formset(current_game)
formset = VoteFormSet(
request.POST,
queryset=Vote.objects.filter(game__round=round, user=user))
Otros consejos
Otra solución es subclasificar BaseModelFormSet y anular el método _construct_forms . Por defecto, el método BaseFormSet _construct_form invoca _construct_forms con un solo argumento, i:
# django/forms/formsets.py
def _construct_forms(self):
# instantiate all the forms and put them in self.forms
self.forms = []
for i in xrange(self.total_form_count()):
self.forms.append(self._construct_form(i))
pero puede haber cualquier número de argumentos de palabras clave:
# django/forms/formsets.py
def _construct_form(self, i, **kwargs):
Entonces, aquí está mi método de vista y formulario que recibe parámetros adicionales en init de _construct_form:
# view
def edit(request, id):
class ActionsFormSet(BaseModelFormSet):
department = request.user.userdata.department.pk
def _construct_forms(self):
self.forms = []
for i in range(self.total_form_count()):
self.forms.append(self._construct_form(i, dep=self.department))
actions_formset = modelformset_factory(Action, form=ActionForm, extra=0, can_delete=True, formset=ActionsFormSet)
...
# form
class ActionForm(forms.ModelForm):
def __init__(self, dep=0, *args, **kwargs):
super(ActionForm, self).__init__(*args, **kwargs)
self.fields['user'].choices = [(u.pk, u.first_name) for u in User.objects.filter(userdata__department=dep)]
class Meta:
model = Action
exclude = ('req',)