Python 创建动态选择字段

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3419997/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 10:58:21  来源:igfitidea点击:

Creating a dynamic choice field

pythondjangodjango-formsdjango-templates

提问by whatWhat

I'm having some trouble trying to understand how to create a dynamic choice field in django. I have a model set up something like:

我在尝试理解如何在 django 中创建动态选择字段时遇到了一些麻烦。我有一个模型设置如下:

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

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

What I'm trying to do is create a choice Field whos values are the waypoints associated with that rider (which would be the person logged in).

我想要做的是创建一个选择字段,其值是与该骑手(即登录的人)相关联的航点。

Currently I'm overriding init in my forms like so:

目前我正在我的表单中覆盖 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()])

But all that does is list all the waypoints, they're not associated with any particular rider. Any ideas? Thanks.

但所做的只是列出所有的航点,它们与任何特定的骑手无关。有任何想法吗?谢谢。

采纳答案by Ashok

you can filter the waypoints by passing the user to the form init

您可以通过将用户传递给表单 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)]
        )

from your view while initiating the form pass the user

从您的角度出发,同时启动表单传递用户

form = waypointForm(user)

in case of model form

在模型形式的情况下

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

回答by Alexander Lebedev

There's built-in solution for your problem: ModelChoiceField.

您的问题有内置的解决方案:ModelChoiceField

Generally, it's always worth trying to use ModelFormwhen you need to create/change database objects. Works in 95% of the cases and it's much cleaner than creating your own implementation.

通常,ModelForm当您需要创建/更改数据库对象时,总是值得尝试使用。在 95% 的情况下都有效,而且比创建自己的实现要干净得多。

回答by Manoj Govindan

How about passing the rider instance to the form while initializing it?

如何在初始化时将骑手实例传递给表单?

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) 

回答by Liang

the problem is when you do

问题是你什么时候做

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 a update request, the previous value will lost!

在更新请求中,之前的值将丢失!

回答by Haroldo_OK

As pointed by Breedly and Liang, Ashok's solution will prevent you from getting the select value when posting the form.

正如 Breedly 和 Liang 所指出的,Ashok 的解决方案将阻止您在发布表单时获得选择值。

One slightly different, but still imperfect, way to solve that would be:

一种稍微不同但仍然不完美的解决方法是:

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)

This could cause some concurrence problems, though.

不过,这可能会导致一些并发问题。

回答by Deil

Underneath working solution with normal choice field. my problem was that each user have their own CUSTOM choicefield options based on few conditions.

在具有正常选择字段的工作解决方案下方。我的问题是每个用户都有自己的 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

回答by Tobias Ernst

If you need a dynamic choice field in django admin; This works for django >=2.1.

如果您需要 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

Hope this helps.

希望这可以帮助。

回答by Zags

You can declare the field as a first-class attribute of your form and just set choices dynamically:

您可以将该字段声明为表单的一级属性,然后动态设置选项:

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

You can also use a ModelChoiceField and set the queryset on init in a similar manner.

您还可以使用 ModelChoiceField 并以类似方式在 init 上设置查询集。