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.