创建一个动态选择字段

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

但是所有这些只是列出了所有的路点,它们并没有与任何特定的骑手联系起来。有什么想法吗? 谢谢。

132247 次浏览

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

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

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

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

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)

问题是你什么时候做

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

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

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

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

正常选择字段下的工作解决方案。 我的问题是,每个用户都有自己基于少数条件的定制选项域选项。

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

如果在 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

希望这个能帮上忙。

您可以将字段声明为表单的一级属性,并在 __init__中动态设置选项:

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。

如果您使用的是 ModelForm,并且希望覆盖自动生成字段的选项,则此方法更为优越。