【问题标题】:Creating a dynamic choice field创建动态选择字段
【发布时间】:2011-03-26 02:26:33
【问题描述】:

我在尝试了解如何在 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()])

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

【问题讨论】:

    标签: python django django-forms django-templates


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 使用 ModelChoiceField 无论它是否是 ModelForm - 它也适用于普通表单。
      • 当您想要获取请求数据时,您会怎么做? waypointForm(request.POST) 不会在第一个中验证,因为要验证的数据不再存在。
      • @Ashok 在这种情况下如何使用 CheckboxSelectMultiple 小部件?特别是对于模型形式。
      • 如果你想使用 CheckboxSelectMultiple 小部件,你需要使用 MultipleChoiceFieldModelMultipleChoiceField。起初,它似乎可以与 ChoiceField 一起使用,但是当您尝试保存表单时,内部结构会损坏。
      • 谢谢@CoreDumpError - 在阅读您的评论(doh!)之前,我已经为此奋斗了近 2 个小时(doh!),这最终使一切正常。其他人,如果您打算将CheckboxSelectMultiple 小部件与此代码一起使用,请注意不要破坏您的表单提交(unicode 问题)。一定要把ChoiceForm改成MultipleChoiceForm
      【解决方案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) 
      

      【讨论】:

        【解决方案4】:

        问题是当你这样做时

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

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

        【讨论】:

          【解决方案5】:

          正如 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)
          

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

          【讨论】:

            【解决方案6】:

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

            【讨论】:

            • 正是我想要的!谢谢!
            • 这让我的生活更轻松.. 非常感谢.. :)
            【解决方案7】:

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

            希望这会有所帮助。

            【讨论】:

              【解决方案8】:

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

              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 上设置查询集。

              【讨论】:

                猜你喜欢
                • 2016-04-18
                • 1970-01-01
                • 2021-02-25
                • 2013-12-14
                • 1970-01-01
                • 2018-01-11
                • 1970-01-01
                • 1970-01-01
                • 2019-01-20
                相关资源
                最近更新 更多