Создание формы CreateForm с вариантами выбора на основе значений базы данных
Я делаю проект на django и у меня есть форма для пользователя, чтобы добавить автомобиль вручную, который будет закреплен за ним. Я также хотел бы иметь возможность для пользователя выбрать автомобиль на основе записей, уже имеющихся в базе данных.
vehicles/models.py
class Vehicle(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
nickname = models.CharField(unique = True, max_length=150)
date_joined = models.DateTimeField(default=timezone.now)
brand = models.CharField(max_length=150)
battery = models.CharField(max_length=150)
model = models.CharField(max_length=150)
def __str__(self):
return self.nickname
def get_absolute_url(self):
return reverse('vehicle-list')
class Meta:
db_table = "vehicles"
Я создал форму, чтобы пользователь мог добавить свои транспортные средства следующим образом:
vehicles/forms.py
class VehicleAddFormManual(forms.ModelForm):
class Meta:
model = Vehicle
fields = ('brand','model', 'battery', 'nickname')
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
self.fields['brand']
self.fields['model']
self.fields['battery']
self.fields['nickname']
Соответствующий вид:
vehicles/views.py
class AddVehicleViewManual(LoginRequiredMixin, CreateView):
model = Vehicle
form_class = VehicleAddFormManual
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
def form_valid(self, form):
form.instance.user = self.request.user
return super().form_valid(form)
Файл html:
<{% extends "blog/base.html" %}
{% block content %}
{% load crispy_forms_tags %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">New Vehicle</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Submit</button>
</div>
</form>
</div>
{% endblock content %}
vehicles/templates/vehicles/vehicle_form.html
Я хочу добавить еще одну форму, в которой у пользователя будет выпадающий список с опциями с марками, моделями и аккумуляторами, которые уже существуют в базе данных. Если в базе данных есть автомобиль с маркой: Tesla, модель: Model 3, батарея: 50 кВтч, то он появится в выпадающем списке в качестве варианта для каждого поля.
Я не уверен как это сделать и извините за вопрос новичка.... Заранее спасибо!
model.py
class DropdownModel(models.Model):
brand = models.CharField(max_length=150)
battery = models.CharField(max_length=150)
model = models.CharField(max_length=150)
def __str__(self):
return self.brand.
form.py
from .models import DropdownModel
all_brand = DropdownModel.objects.values_list('brand','brand')
all_battery = DropdownModel.objects.values_list('battery','battery')
all_model= DropdownModel.objects.values_list('model','model')
class DropdownForm(forms.ModelForm):
class Meta:
model = DropdownModel
fields = "__all__"
widgets = {
'brand':forms.Select(choices=all_brand),
'battery':forms.Select(choices=all_battery),
'model':forms.Select(choices=all_model),
}
index.html
{% extends "base.html" %}
{% load static %}
{% block title %}
Index | Page
{% endblock title %}
{% block body %}
{{form.as_p}}
{% endblock body %}
Выход-
Примечание- если вы не видите обновленные значения в выпадающем списке, перезагрузите сервер, потому что localhost не поддерживает автоматическое обновление значений в выпадающем списке, оно поддерживается на живом сервере
Спасибо
Однажды мне пришлось делать нечто подобное, но мне нужна была форма, которая имела по одному флажку для каждого элемента в списке строк, предоставленных извне. Я не знаю, является ли это самым чистым способом, но я использовал метаклассы python:
class SockSelectForm(forms.Form):
@staticmethod
def build(sock_names):
fields = {'sock_%s' % urllib.parse.quote(name):
forms.BooleanField(label=name, required=False)
for name in sock_names}
sub_class = type('DynamicSockSelectForm', (SockSelectForm,), fields)
return sub_class()
В моем методе get() я инстанцирую его как:
form = SockSelectForm.build(names)
а соответствующая обработка формы в методе post() такова:
form = SockSelectForm(request.POST)
Я подозреваю, что если вы заглянете под обложку ModelForm в Django, то увидите нечто подобное, но я не смог использовать ModelForm, потому что он слишком тесно связан с системой моделей для того, что мне нужно было сделать.