问题
I have two querysets: type
and age_group
.
type queryset:
<QuerySet [<Type: Cat>, <Type: Dog>, <Type: Other>]>
age_group queryset:
<QuerySet [<AgeGroup: Young>, <AgeGroup: Baby>, <AgeGroup: Adult>, <AgeGroup: Senior>]>
I loop through these from within my template form so that I can grab the pk when one has been selected, but I cannot capture the variable from within the for loop. How do I capture a variable from within a for loop when using Django? I want to capture pk for type
and pk for age_group
and then use both to filter the model Animal
and return a filtered list that matches the user's preferences. A directory search function, essentially.
Template:
{% extends 'base.html' %}
{% block content %}
<h1>Animal Search</h1>
<form class="form-inline" action= '.' method="post">
{% csrf_token %}
<select name= "TypeSearch" class="custom-select my-1 mr-sm-2" id="animal_list_type">
<label class="sr-only type" for="animal_list_type">SEARCH</label>
{% for i in animal_type_list %}
<option value="{{i.pk}}">{{i}}</option> #how to capture the selected pk??
{% endfor %}
</select>
<select name="AgeSearch" class="custom-select my-1 mr-sm-2" id="animal_list_ageGroup">
<label class="sr-only ageLabel" for="animal_list_ageGroup">SEARCH</label>
{% for j in age_group_list %}
<option value="{{j.pk}}">{{j}}</option> #how to capture the selected pk??
{% endfor %}
</select>
<input type="submit" value="SEARCH" onclick="window.location='{% url 'animals:matches_list' pk=4 %}'; return false;">
<input type="submit" onclick="window.location='{% url 'animals:animals' %}'; return false;" value="Cancel">
</form>
{% endblock %}
views.py
class VisitorSearchView(View):
def get(self, request, pk=None):
#first tried ModelForm but couldn't figure out how to capture and iterate through one field of value options at a time
animalList = Animal.type.get_queryset()
animalList2 = Animal.ageGroup.get_queryset()
context = {
"animal_type_list": animalList,
"age_group_list": animalList2
}
return render(request, "animals/landing.html", context)
def post(self, request, pk=None):
theForm1 = AnimalSearchForm(request.POST)
success_url = reverse_lazy('animals:matches_list')
print(pk)
print(theForm1)
filler_for_now = Animals.objects.all()
context = {
'theMatches': filler_for_now
}
return render(request, success_url, context)
model.py
class Animal(models.Model):
name = models.CharField(max_length=500, blank=False, null=False)
type = models.ForeignKey(Type, on_delete=models.SET_NULL, blank=False, null=True)
ageGroup = models.ForeignKey(AgeGroup, max_length=300, on_delete=models.SET_NULL, blank=False, null=True)
age = models.PositiveIntegerField(blank=False, null=False)
sex = models.CharField(max_length=100, choices=SEX, blank=False, null=False, default='NA')
breedGroup = models.ManyToManyField(BreedGroup, blank=False)
breed = models.ManyToManyField(Breed, blank=False)
tagLine = models.CharField(max_length=300, blank=False, null=False)
goodWithCats = models.BooleanField(blank=False, null=False, default='Not Enough Information')
goodWithDogs = models.BooleanField(null=False, blank=False, default='Not Enough Information')
goodWKids = models.BooleanField(null=False, blank=False, default='Not Enough Information')
urls.py
app_name = 'animals'
urlpatterns = [
path('', views.AnimalListView.as_view(), name='animals'),
path('landing/', views.VisitorSearchView.as_view(), name='landing'),
path('matches/<int:pk>', views.VisitorSearchView.as_view(), name='matches_list'),
]
forms.py #(originally tried to use ModelForm but couldn't figure out how to grab the pk for both chooseType
and chooseAge
fields so chose to try to just use querysets from view)
class AnimalSearchForm(ModelForm):
chooseType = ModelChoiceField(queryset=Animal.objects.values_list('type', flat=True).distinct(),empty_label=None)
chooseAge = ModelChoiceField(queryset=Animal.objects.values_list('ageGroup', flat=True).distinct(), empty_label=None)
class Meta:
model = Animal
exclude = '__all__'
Outside of Django, this would be a simple problem to solve. How do I capture a variable from within a for loop when using Django? I have tried to instantiate a variable outside the for-loop and then update that based off selection from within, but it seems that this cannot be done via the template...?
回答1:
Well the real issue here is that you really should be using FormView
to display a form together with DetailView
to display model data, in this particular case you should do something like this:
views.py
from django.views.generic import FormView, DetailView
class VisitorSearchView(FormView, DetailView):
model = Animal
template_name = 'animals/landing.html'
form_class = AnimalSearchForm
def form_valid(self, form):
data = form.cleaned_data # Dict of submitted data
# handle form validation and redirect
def get_context_data(self, request):
context = super(VisitorSearchView, self).get_context_data(**kwargs)
animals = Animal.objects.all() # or use a custom filter
context['animals'] = animals
return context
Then in your landing.html
where you want a list of animal types
:
{% for animal in animals %}
{{ animal.type }}
{% endfor %}
and where you want a list of animal ages
:
{% for animal in animals %}
{{ animal.age }}
{% endfor %}
declare your form
normally as you would.
回答2:
I think you need to remove the dot from the action
attribute. Empty string in action use the current URL for form submission. Form opening line will be like
<form class="form-inline" action= '' method="post">
来源:https://stackoverflow.com/questions/65483354/how-best-to-capture-variables-from-within-a-for-loop-in-django-template