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
Creating a dynamic choice field
提问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 上设置查询集。

