I have 3 dropdowns that work fine. My goal is to click on the button and print the text of the third dropdown inside the textarea (def result
and result.html
), precisely inside a sentence in def test1
. For example if I select Madrid, I will print "The selected trip is Madrid".
I don't want to pass the sentence directly (with "Madrid" inside it) into def result
(which is the function of result.html
, i.e. of the textarea). I don't want the sentence construction (with "Madrid" in it) to be built inside the def result
function
I want the text of the third dropdown (e.g. "Madrid"), to become a placeholder that is passed first in the def test1
function. It is here that the sentence will be created which will subsequently be printed in the textarea (def result
). I need this because in future in def test1
I will also call other sentences from other python files. So it's like the def test1
function acts as a sort of filter between the dropdowns and the textarea (def result
).
I don't get any errors, but the sentence doesn't print. I think the problem is because def test1
fails to retrieve options
from the third dropdown (e.g. "Madrid").
models.py
from django.db import models
class Country(models.Model):
name = models.CharField(max_length=40)
def __str__(self):
return self.name
class City(models.Model):
country = models.ForeignKey(Country, on_delete=models.CASCADE)
name = models.CharField(max_length=40)
def __str__(self):
return self.name
class FullRecord(models.Model):
country = models.ForeignKey(Country, on_delete=models.CASCADE)
city_departure = models.ForeignKey(City, on_delete=models.CASCADE, related_name="city_departure")
city_destination = models.ForeignKey(City, on_delete=models.CASCADE, related_name="city_destination")
@property
def departure_destination(self):
return f"{self.city_departure}-{self.city_destination}"
def __str__(self):
return self.country.name
views.py
**from django.shortcuts import render
from .models import FullRecord, Country
def trip_selector(request):
if "Hx-Request" in request.headers:
trips = FullRecord.objects.none()
if request.headers["Hx-Trigger"] == "id_trip":
country_id = request.GET.get("country")
if country_id != "":
trips = FullRecord.objects.filter(country_id=country_id)
return render(request, "trips.html", {"trips": trips})
elif request.headers["Hx-Trigger"] == "id_extract_single_city":
selected_trip = request.GET.get("trips")
extracted_cities = []
if selected_trip != "":
trip = FullRecord.objects.get(id=int(selected_trip))
trip_with_combined_names = trip.departure_destination
split_trip = trip_with_combined_names.split("-")
extracted_cities = split_trip
return render(request, "extract_single_city.html", {"options": extracted_cities})
else:
countries = Country.objects.all()
return render(request, "form.html", {"countries": countries})**
#Create sentence
def test1(request):
sentence = ["The selected trip is ", "Congratulations you have selected the trip ", "You have currently selected travel ", "The currently selected trip is "]
return f"{random.choice(sentence)} {options}" #ERROR????
#Print in textarea
def result(request):
test_print_in_result = test1(request)
return render(request,"result.html", {"test_print_in_result": test_print_in_result})
urls.py
**from django.urls import path
from . import views
urlpatterns = [
path("", views.trip_selector, name="trips")
]**
admin.py
from django.contrib import admin
# Register your models here.
from .models import Country, City, FullRecord
class Prossima(admin.ModelAdmin):
list_display = ['id', 'country','departure_destination']
admin.site.register(FullRecord, Prossima)
admin.site.register(Country)
admin.site.register(City)
base.html
:
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>University</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
<!-- HTMX -->
<script src="https://unpkg.com/[email protected]/dist/htmx.min.js"></script>
</head>
<body>
<div class="container mt-4">
{% block main-content %}
{% endblock %}
</div>
<!-- evitare che le richieste hx-post incorrano in errori CSRF con le viste Django -->
<script>
document.body.addEventListener('htmx:configRequest', (event) => {
event.detail.headers['X-CSRFToken'] = '{{ csrf_token }}'; //insert csrf token when performing AJAX request
})
</script>
</body>
</html>
forms.html
:
{% extends 'base.html' %}
{% block main-content %}
<div class="flex justify-between px-10 gap-5 mt-5">
<div class="flex flex-col w-full">
<!-- First Combobox -->
<label for="id_country">Country</label>
<select name="country" id="id_country">
<option value="">Please select</option>
{% for country in countries %}
<option value="{{ country.pk }}">{{ country.name }}</option>
{% endfor %}
</select>
</div>
<div class="flex flex-col w-full">
<!-- Second Combobox ??????? (non lo so)-->
<label for="id_trip">Trip</label>
<select name="trips" id="id_trip"
hx-get="{% url 'trips' %}"
hx-include="[name=country]"
hx-indicator=".htmx-indicator"
hx-trigger="change from:#id_country">
</select>
</div>
<!-- Third Combobox -->
<div class="flex flex-col w-full">
<label for="id_extract_single_city">Extract single city</label>
<select name="extract_single_city" id="id_extract_single_city"
hx-get="{% url 'trips' %}"
hx-include="[name=trips]"
hx-indicator=".htmx-indicator"
hx-trigger="change from:#id_trip">
</select>
</div>
</div>
<!-- Textarea-->
{% include "result.html" %}
<!-- Button-->
<button type="button" class="mybtn" name="btn" hx-get="{% url 'result' %}" hx-swap="outerHTML" hx-target="#id_result" hx-indicator=".htmx-indicator">Button 1</button>
{% endblock main-content %}
trips.html
:
<option value="">Please select</option>
{% for trip in trips %}
<option value="{{ trip.id }}">{{ trip.city_departure }}-{{ trip.city_destination }}</option>
{% endfor %}
extract_single_city.html
<option value="">Please select</option>
{% for i in options %}
<option value="{{ i }}">{{ i }}</option>
{% endfor %}
result.html
:
<textarea name="result" id="id_result">{{ test_print_in_result }}</textarea>
Quite easy to implement actually.
Update forms.html
:
The important part here is that you should define the textarea field rather than returning it as a seperate template (it's unnecessary). Also, include the value of the extract_single_city
select field by referencing its id in hx-include
attribute. I don't know if you want to be able to insert multiple messages into the textarea, I assumed you do that's why I changed the htmx swap technique to beforeend
so the new result is added below the existing ones. I added readonly
atribute to the textarea tag so it's not editable.
.....
<div class="flex flex-col w-1/2 justify-end">
<button class="bg-green-300 p-2 rounded"
type="button"
hx-get="{% url 'result' %}"
hx-include="#id_extract_single_city"
hx-target="#id_result"
hx-swap="beforeend">Submit
</button>
</div>
<div class="py-2 px-10 h-96 mt-5">
<textarea name="result" id="id_result" readonly class="w-full h-full rounded px-2 py-3"></textarea>
</div>
....
Update the views
:
Please notice the create_sentence
function is expecting a 'city' argument so it can create an appropriate sentence. You access the city value (supplied the htmx request) in the result function which returns an HttpResponse rather than a render function. This is because you don't need a template to return simple text.
from django.http import HttpResponse
# Create sentence
def create_sentence(request):
sentence = random.choice(
[
"The selected trip is",
"Congrats, you have selected the trip",
"You have currently selected to travel",
"The currently selected trip is",
]
)
city = request.GET.get("extract_single_city")
return f"{sentence} {city} \n"
#Print in textarea
def result(request):
result = create_sentence(request)
return HttpResponse(result)
That should work.