動的選択フィールドの作成


136

djangoで動的選択フィールドを作成する方法を理解しようとして問題が発生しています。私は次のようなモデルを設定しています:

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

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

私がやろうとしていることは、選択したフィールドを作成することです。値は、そのライダー(ログインしている人)に関連付けられたウェイポイントです。

現在、私は自分のフォームのinitを次のようにオーバーライドしています:

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

ただし、すべてのウェイポイントをリストするだけで、特定のライダーに関連付けられているわけではありません。何か案は?ありがとう。

回答:


191

ユーザーをフォーム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)]
        )

あなたの見解から、フォームを開始しながらユーザーを渡します

form = waypointForm(user)

モデルフォームの場合

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
ModelFormであるかどうかに関係なく、ModelChoiceFieldを使用します。通常のフォームでも機能します。
Daniel Roseman、2010

9
ただし、リクエストデータを取得したい場合はどうしますか?waypointForm(request.POST)は、最初の検証では検証されません。検証するデータがないためです。
ブリードリー2013

1
@AshokこのインスタンスでCheckboxSelectMultipleウィジェットをどのように使用できますか?特にmodelformについて。
wasabigeek

2
CheckboxSelectMultipleこれでウィジェットを使用したい場合は、MultipleChoiceFieldまたはを使用する必要がありModelMultipleChoiceFieldます。最初はで動作するようですChoiceFieldが、フォームを保存しようとすると内部が壊れます。
coredumperror 2016年

1
@CoreDumpErrorに感謝-コメントを読む前にこれを2時間近く戦いました(doh!)。これでようやくすべてが機能しました。その他、CheckboxSelectMultipleこのコードでウィジェットを使用する場合は、フォーム送信(Unicodeの問題)に違反しないように注意してください。必ず変更ChoiceFormしてくださいMultipleChoiceForm
2016

11

あなたの問題のための組み込みのソリューションがあります:ModelChoiceField

一般に、ModelFormデータベースオブジェクトを作成または変更する必要がある場合は、常に使用する価値があります。ケースの95%で機能し、独自の実装を作成するよりもはるかにクリーンです。


8

問題はあなたがするときです

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

更新リクエストでは、以前の値は失われます!


3

初期化中にライダーインスタンスをフォームに渡すのはどうですか?

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

通常の選択フィールドを持つ作業ソリューションの下。私の問題は、いくつかの条件に基づいて、各ユーザーが独自のCUSTOM choicefieldオプションを持っていることでした。

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

まさに私が探していたもの!ありがとう!
ラプター

これは私の人生を楽にしてくれた..
どうも

1

ブリードリーとリャンが指摘したように、アショクのソリューションでは、フォームを投稿するときに選択値を取得できません。

それを解決するためのわずかに異なるが、それでも不完全な方法は、

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)

ただし、これにより、いくつかの並行性の問題が発生する可能性があります。


1

フィールドをフォームのファーストクラスの属性として宣言し、選択肢を動的に設定することができます:

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

同様に、ModelChoiceFieldを使用して、initにクエリセットを設定することもできます。


0

django adminで動的な選択フィールドが必要な場合; これは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

お役に立てれば。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.