创建动态选择字段


136

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

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

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

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

目前,我以如下形式覆盖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()])

但是所有要做的就是列出所有路标,它们与任何特定的骑手都没有关联。有任何想法吗?谢谢。

Answers:


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

9
但是,当您想获取请求数据时该怎么办?waypointForm(request.POST)将不会在第一个中进行验证,因为不再需要进行验证的数据。
2013年

1
@Ashok在这种情况下如何使用CheckboxSelectMultiple小部件?特别是对于模型形式。
wasabigeek

2
如果要CheckboxSelectMultiple与此一起使用小部件,则需要使用MultipleChoiceFieldModelMultipleChoiceField。刚开始,它似乎可以使用ChoiceField,但是当您尝试保存表单时,内部结构会损坏。
coredumperror

1
谢谢@CoreDumpError-在阅读您的评论之前,这已经花了将近2个小时(doh!),这终于使一切正常。其他人,如果计划将CheckboxSelectMultiple小部件与该代码一起使用,请当心破坏表单提交(unicode问题)。请务必更改ChoiceFormMultipleChoiceForm
播出


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选择字段选项。

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

正是我想要的!谢谢!
猛禽队'18

这使我的生活更加轻松..非常感谢.. :)
Aravind R Pillai

1

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

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

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上设置queryset。


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

希望这可以帮助。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.