Создание поля динамического выбора
У меня возникли проблемы, пытаясь понять, как создать поле динамического выбора в 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()])
Но все, что делает, это перечисляет все путевые точки, они не связаны с каким-либо конкретным райдером. Есть идеи? Благодарю.
6 ответов
Вы можете фильтровать путевые точки, передавая пользователю форму инициализации
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
когда вам нужно создать / изменить объекты базы данных. Работает в 95% случаев, и это намного чище, чем создание собственной реализации.
Проблема в том, когда вы делаете
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)])
в запросе на обновление предыдущее значение будет потеряно!
Вы можете объявить поле как первоклассный атрибут вашей формы и просто динамически устанавливать варианты:
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 и аналогичным образом задать набор запросов при инициализации.
Как насчет передачи экземпляра райдера в форму при его инициализации?
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)
If you need a dynamic choice field in django admin; This works for 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.
Под рабочим раствором с нормальным выбором поля. Моя проблема заключалась в том, что каждый пользователь имеет свои собственные опции поля выбора 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
Как указали Breedly и Liang, решение Ashok не позволит вам получить значение select при публикации формы.
Один немного другой, но все же несовершенный способ решения проблемы:
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)
Это может вызвать некоторые проблемы с совпадением.