Django Passando i parametri del modulo personalizzato a ModelFormset
-
06-07-2019 - |
Domanda
Il mio problema è simile a Django Passaggio dei parametri del modulo personalizzato al formset
Ho queste classi
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"),)
E ho definito il mio 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
E lo uso così:
VoteFormSet = modelformset_factory(Vote, form=mymodelformset_factory(v), extra=0)
formset = VoteFormSet(request.POST, queryset=Vote.objects.filter(game__round=round, user=user))
Questo visualizza il modulo:
casella a discesa di Gioco (i) nel Round specificato e si suppone che visualizzi 3 pulsanti di opzione per le Quote ma non so cosa passare come parametro a mymodelformset_factory .. Se v = Game.objects. get (pk = 1) ovviamente mostra solo il gioco con pk = 1 per TUTTI i giochi, ciò di cui ho bisogno è v = Game.objects.get (pk = " gioco che è collegato alle probabilità riguardanti ") se catturi la mia deriva ..
Soluzione
Penso che tu voglia apportare alcune modifiche alla tua funzione di fabbrica personalizzata. Dovrebbe restituire la classe formset, non il modulo. Che ne dici di questo:
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)
Quindi nel tuo codice di visualizzazione:
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))
Altri suggerimenti
Un'altra soluzione è sottoclassare BaseModelFormSet e sovrascrivere il metodo _construct_forms . Per impostazione predefinita, il metodo BasecormSet _construct_form chiama in _construct_forms con un solo argomento, 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))
ma può esserci un numero qualsiasi di parole chiave args:
# django/forms/formsets.py
def _construct_form(self, i, **kwargs):
Quindi, ecco il mio metodo di visualizzazione e il modulo che riceve parametri aggiuntivi in ?? init da _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',)