Creazione di un campo di scelta dinamica


136

Ho dei problemi nel cercare di capire come creare un campo di scelta dinamica in Django. Ho un modello impostato come:

class rider(models.Model):
     user = models.ForeignKey(User)
     waypoint = models.ManyToManyField(Waypoint)

class Waypoint(models.Model):
     lat = models.FloatField()
     lng = models.FloatField()

Quello che sto cercando di fare è creare una scelta Campo in cui i valori sono i waypoint associati a quel ciclista (che sarebbe la persona che ha effettuato l'accesso).

Attualmente sto sostituendo init nei miei moduli in questo modo:

class waypointForm(forms.Form):
     def __init__(self, *args, **kwargs):
          super(joinTripForm, self).__init__(*args, **kwargs)
          self.fields['waypoints'] = forms.ChoiceField(choices=[ (o.id, str(o)) for o in Waypoint.objects.all()])

Ma tutto ciò che fa è elencare tutti i waypoint, non sono associati ad alcun pilota particolare. Qualche idea? Grazie.

Risposte:


191

è possibile filtrare i waypoint passando l'utente al modulo init

class waypointForm(forms.Form):
    def __init__(self, user, *args, **kwargs):
        super(waypointForm, self).__init__(*args, **kwargs)
        self.fields['waypoints'] = forms.ChoiceField(
            choices=[(o.id, str(o)) for o in Waypoint.objects.filter(user=user)]
        )

dalla tua visualizzazione durante l'avvio del modulo passa l'utente

form = waypointForm(user)

in caso di modello

class waypointForm(forms.ModelForm):
    def __init__(self, user, *args, **kwargs):
        super(waypointForm, self).__init__(*args, **kwargs)
        self.fields['waypoints'] = forms.ModelChoiceField(
            queryset=Waypoint.objects.filter(user=user)
        )

    class Meta:
        model = Waypoint

20
Usa ModelChoiceField indipendentemente dal fatto che sia un ModelForm - funziona anche su moduli normali.
Daniel Roseman,

9
Cosa fai quando vuoi ottenere i dati della richiesta? waypointForm (request.POST) non verrà convalidato nel primo, perché i dati per la convalida non sono più presenti.
Breedly,

1
@Ashok Come si può usare il widget CheckboxSelectMultiple in questa istanza? Soprattutto per il modello.
wasabigeek,

2
Se vuoi usare il CheckboxSelectMultiplewidget con questo, ti consigliamo di usare MultipleChoiceFieldo ModelMultipleChoiceField. All'inizio sembra funzionare ChoiceField, ma gli interni si romperanno quando si tenta di salvare il modulo.
coredumperror,

1
Grazie @CoreDumpError - ho combattuto per quasi 2 ore prima di leggere il tuo commento (doh!) E alla fine ha fatto funzionare tutto. Altri, attenzione a interrompere l'invio del modulo (problemi di Unicode) se prevedi di utilizzare il CheckboxSelectMultiplewidget con questo codice. Assicurati di passare ChoiceFormaMultipleChoiceForm
leggermente il

11

C'è una soluzione integrata per il tuo problema: ModelChoiceField .

In genere, vale sempre la pena provare a utilizzare ModelFormquando è necessario creare / modificare oggetti di database. Funziona nel 95% dei casi ed è molto più pulito rispetto alla creazione della propria implementazione.


8

il problema è quando lo fai

def __init__(self, user, *args, **kwargs):
    super(waypointForm, self).__init__(*args, **kwargs)
    self.fields['waypoints'] = forms.ChoiceField(choices=[ (o.id, str(o)) for o in Waypoint.objects.filter(user=user)])

in una richiesta di aggiornamento, il valore precedente andrà perso!


3

Che ne dici di passare l'istanza del pilota al modulo durante l'inizializzazione?

class WaypointForm(forms.Form):
    def __init__(self, rider, *args, **kwargs):
      super(joinTripForm, self).__init__(*args, **kwargs)
      qs = rider.Waypoint_set.all()
      self.fields['waypoints'] = forms.ChoiceField(choices=[(o.id, str(o)) for o in qs])

# In view:
rider = request.user
form = WaypointForm(rider) 

2

Sotto la soluzione di lavoro con campo di scelta normale. il mio problema era che ogni utente aveva le proprie opzioni del campo choice CUSTOM in base a poche condizioni.

class SupportForm(BaseForm):

    affiliated = ChoiceField(required=False, label='Fieldname', choices=[], widget=Select(attrs={'onchange': 'sysAdminCheck();'}))

    def __init__(self, *args, **kwargs):

        self.request = kwargs.pop('request', None)
        grid_id = get_user_from_request(self.request)
        for l in get_all_choices().filter(user=user_id):
            admin = 'y' if l in self.core else 'n'
            choice = (('%s_%s' % (l.name, admin)), ('%s' % l.name))
            self.affiliated_choices.append(choice)
        super(SupportForm, self).__init__(*args, **kwargs)
        self.fields['affiliated'].choices = self.affiliated_choice

Esattamente quello che stavo cercando! Grazie!
Raptor

questo mi ha semplificato la vita .. Grazie mille .. :)
Aravind R Pillai,

1

Come sottolineato da Breedly e Liang, la soluzione di Ashok ti impedirà di ottenere il valore selezionato quando invii il modulo.

Un modo leggermente diverso, ma ancora imperfetto, di risolverlo sarebbe:

class waypointForm(forms.Form):
    def __init__(self, user, *args, **kwargs):
        self.base_fields['waypoints'].choices = self._do_the_choicy_thing()
        super(waypointForm, self).__init__(*args, **kwargs)

Ciò potrebbe tuttavia causare alcuni problemi di concorrenza.


1

Puoi dichiarare il campo come un attributo di prima classe del tuo modulo e impostare dinamicamente le scelte:

class WaypointForm(forms.Form):
    waypoints = forms.ChoiceField(choices=[])

    def __init__(self, user, *args, **kwargs):
        super().__init__(*args, **kwargs)
        waypoint_choices = [(o.id, str(o)) for o in Waypoint.objects.filter(user=user)]
        self.fields['waypoints'].choices = waypoint_choices

È inoltre possibile utilizzare ModelChoiceField e impostare il queryset su init in modo simile.


0

Se hai bisogno di un campo di scelta dinamica in django admin; Funziona con django> = 2.1.

class CarAdminForm(forms.ModelForm):
    class Meta:
        model = Car

    def __init__(self, *args, **kwargs):
        super(CarForm, self).__init__(*args, **kwargs)

        # Now you can make it dynamic.
        choices = (
            ('audi', 'Audi'),
            ('tesla', 'Tesla')
        )

        self.fields.get('car_field').choices = choices

    car_field = forms.ChoiceField(choices=[])

@admin.register(Car)
class CarAdmin(admin.ModelAdmin):
    form = CarAdminForm

Spero che questo ti aiuti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.