Django foreign key как опции для автозаполнения, ошибка: Выберите правильный вариант
Заранее благодарю за помощь. Я создаю свой первый проект Django, приложение для продажи билетов, в котором будет более 100 пунктов на выбор.
Я пытаюсь отобразить список элементов (объекты с внешним ключом) для выбора пользователем при создании билета в поле автозаполнения MDBootstrap. Элементы имеют как имя, так и ID, и я хочу, чтобы оба отображались в опциях автозаполнения, когда пользователь осуществляет поиск.
Моя форма работает, когда я отображаю только 'item_id' из модели Item в данных автозаполнения (находится в тегах скрипта внизу шаблона). Но когда я отображаю строку с 'item_name' и 'item_id' (как показано ниже), моя форма не отправляется и я получаю ошибку "Select a valid choice. Этот выбор не является одним из доступных вариантов."
Как я могу отобразить и 'item_name' и 'item_id' из модели Item в опциях автозаполнения, но затем заставить мою форму правильно отправить, распознав 'item_id' для своего поля внешнего ключа 'item'?
модели (каждая из этих моделей находится в отдельном приложении в проекте django)
class Item(models.Model):
item_name = models.CharField(max_length=200)
item_id = models.CharField(max_length=200, primary_key=True)
class Ticket(models.Model):
ticket_id = models.AutoField(primary_key=True, null=False, blank=False)
item = models.ForeignKey(Item, on_delete=models.PROTECT, null=False, blank=False, related_name="tickets")
view
def TicketSubmit(request):
items = Item.objects.all()
if request.method == "POST":
item = request.POST.get("item")
form = TicketSubmitForm(request.POST)
photoform = TicketImageForm(request.POST or None)
files = request.FILES.getlist("ticket_photo")
if form.is_valid():
f = form.save(commit=False)
f.item = item
for i in files:
TicketPhoto.objects.create(ticket=f, ticket_photo=i)
messages.success(request, "Success! New Ticket Created")
return HttpResponseRedirect(reverse_lazy("home"))
else:
print(form.errors)
else:
form = TicketSubmitForm()
photoform = TicketImageForm()
context = {"form": form, "photoform": photoform, "items": list(items)}
return render(request, "home.html", context)
form
class TicketSubmitForm(forms.ModelForm):
class Meta:
model = Ticket
fields = ["item", "op_name", "ticket_text"]
widgets = {
"created_at": forms.HiddenInput,
"completed": forms.HiddenInput,
"item": forms.TextInput(
attrs={
"class": "form-control",
"id": "form11",
}
),
"op_name": forms.TextInput(
attrs={
"class": "form-control",
"id": "op_nameInput",
"placeholder": "Enter your name here",
}
),
"ticket_text": forms.Textarea(
attrs={
"class": "form-control",
"placeholder": "Write a few words about the issue here",
"rows": "4",
}
),
}
main.js
const basicAutocomplete = document.querySelector('#basic');
const dataFilter = (value) => {
return data.filter((item) => {
return item.toLowerCase().startsWith(value.toLowerCase());
});
};
new mdb.Autocomplete(basicAutocomplete, {
filter: dataFilter
});
шаблон
<form id="ticket_form" role="form" action="" method="post" enctype="multipart/form-data" class="">{% csrf_token %}
<div id="basic" class="form-outline mx-5 mb-2">
{{form.item}}
<label class="form-label" for="form1">Find Item</label>
</div>
#other form fields and submit button
</form>
<script>
const data = [{% for i in items %}'{{ i.item_name }} | ID: {{ i.item_id }}', {% endfor %}];
</script>
Ошибка заключается в том, что вы создаете другую строку для анализа данных при получении данных из формы, а не ту, которую ожидает Django, которая является уникальным идентификатором или вашим первичным ключом.
Это скорее проблема дизайна, но у вас есть несколько доступных вариантов.
Можно было бы просто, перед разбором данных, когда выбирается элемент, например, 'LT7 - Large Tractor 7', иметь шаблон Regex
, чтобы адаптировать входные данные к тому, что нужно Django для работы с вашей моделью, или еще проще, разделить str на -
. и взять первый элемент, который будет первичным ключом, который вам нужен
pk: str = input_from_form_string.split(' - ')[0] # Your LT7 will be in this variable
Является более простым способом достижения цели.
Я смог исправить это следующим образом.
if request.method == "POST":
updated_request = request.POST.copy()
item = request.POST.get("item")
item = item.split("ID:")[1].strip()
updated_request.update({"item": item})
form = TicketSubmitForm(updated_request)
photoform = TicketImageForm(request.POST or None)
files = request.FILES.getlist("ticket_photo")
if form.is_valid():
f = form.save()
for i in files:
TicketPhoto.objects.create(ticket=f, ticket_photo=i)
messages.success(request, "Success! New Ticket Created")
return HttpResponseRedirect(reverse_lazy("home"))
else:
print(form.errors)
else:
form = TicketSubmitForm()
photoform = TicketImageForm()
context = {"form": form, "photoform": photoform, "items": list(items)}
return render(request, "home.html", context)
Спасибо @AlexVergara за то, что направил меня в нужное русло.