web-dev-qa-db-fra.com

Création d'un champ de choix dynamique

J'ai du mal à comprendre comment créer un champ de choix dynamique dans Django. J'ai un modèle mis en place quelque chose comme:

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

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

Ce que j'essaie de faire est de créer un champ de choix dont les valeurs sont les points de cheminement associés à ce coureur (ce serait la personne connectée).

Actuellement, je remplace init dans mes formulaires de la manière suivante:

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()])

Mais tout ce que cela fait est de lister tous les waypoints, ils ne sont associés à aucun pilote en particulier. Des idées? Merci.

127
whatWhat

vous pouvez filtrer les points de passage en passant l'utilisateur au formulaire 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)]
        )

de votre point de vue tout en lançant le formulaire passe l'utilisateur

form = waypointForm(user)

en cas de modèle

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
179
Ashok

Il existe une solution intégrée à votre problème: ModelChoiceField .

Généralement, il vaut toujours la peine d'essayer d'utiliser ModelForm lorsque vous devez créer/modifier des objets de base de données. Fonctionne dans 95% des cas et c'est beaucoup plus propre que de créer votre propre implémentation.

10
Alexander Lebedev

le problème est quand vous faites

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)])

dans une demande de mise à jour, la valeur précédente sera perdue!

7
Liang

Que diriez-vous de passer l'instance de pilote au formulaire lors de son initialisation?

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) 
4
Manoj Govindan

Sous la solution de travail avec le champ de choix normal. mon problème était que chaque utilisateur a ses propres options de champ de choix CUSTOM en fonction de quelques conditions.

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
2
Deil

Comme l'ont indiqué Breedly et Liang, la solution d'Ashok vous empêchera d'obtenir la valeur choisie lors de la publication du formulaire.

Une façon légèrement différente, mais toujours imparfaite, de résoudre ce problème serait:

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)

Cela pourrait toutefois causer des problèmes de concurrence.

1
Haroldo_OK

Si vous avez besoin d’un champ de choix dynamique dans Django admin; Ceci fonctionne pour 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

J'espère que cela t'aides.

0
Tobias Ernst