问题
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