I have a Profile
model with a ManyToManyField
on another model Specialty
.
I want to have a simple search on the Profile
model against specialties and return matching profiles. As it stands, my form displays in my template correctly, but I can't get anything after the submission.
models.py
:
from django.db import models
from django.conf import settings
class Specialty(models.Model):
title = models.CharField(max_length=255)
class Meta:
verbose_name_plural = 'Specialties'
def __unicode__(self):
return u"%s" % self.title
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
specialties = models.ManyToManyField(Specialty, blank=True)
def __unicode__(self):
return u"%s" % (self.user.username)
def get_absolute_url(self):
return reverse("profile_detail", args=[str(self.user.username)])
forms.py
:
from django import forms
from .profiles.models import Profile, Specialty
class ProfileSearchForm(forms.ModelForm):
specialty = forms.ModelMultipleChoiceField(queryset=Specialty.objects.all(), widget=forms.CheckboxSelectMultiple, required=False)
class Meta:
model = Profile
fields = ('specialty',)
views.py
:
from django.views.generic.edit import FormView
from django.core.urlresolvers import reverse_lazy
from .forms import ProfileSearchForm
from .profiles.models import Profile
class IndexView(FormView):
template_name = 'index.html'
form_class = ProfileSearchForm
success_url = reverse_lazy('index')
def form_valid(self, form):
specialty = form.cleaned_data['specialty']
self.profile_list = Profile.objects.filter(specialty__in=specialty)
return super(IndexView, self).form_valid(form)
index.html
:
<form action="{% url 'index' %}" method="get">
{{ form.as_p }}
<p><input type="submit" value="Search"></p>
</form>
<ul>
{% for profile in profile_list %}
<li><a href="{{ profile.get_absolute_url }}">{{ profile.user.get_full_name }}</a></li>
{% endfor %}
</ul>
I have a feeling it has to do with self.profile_list
. I don't know if/how it should go into a get_extra_context
. It can't exist on the first visit, so I don't know how to make it exist or pass it around. I'm also not sure if the Profile.objects.filter(specialty__in=specialty)
is quite the right way to field lookup on a many-to-many field.
I'm also open to other search suggestions like Haystack if they have advantages. I prefer a group of checkboxes, which I don't think Haystack can handle via faceting.
Thanks, Gergo and Cameron. I got it fixed now. You were right about that one problem, but there were quite a few steps left to go.
ListView
plus the ability to do a simple search, which should be a FormMixin
that lets me add form_class
and success_url
, instead of it all as a FormView
. model
is specified in a ListView
, the view blows away the context, so form
never reaches the template. get_context_data
needs to add the form back to the context, of which the docs have an example . form_valid
should be removed because a search is never a POST request, despite what the docs say under the "Note" in FormMixin
requiring form_valid
and form_invalid
. get_queryset
to either get a default queryset via model
or read the GET request's specialties
value and filter the results appropriately. get_form_kwargs
needs to pass the current request to the form so initial form values can remain after a page refresh. The tricky part is that when using ModelMultipleChoiceField
, you have to use request.GET
's getlist
and not get
method to read that list of values. All together now...
forms.py
:
from django import forms
from .profiles.models import Profile, Specialty
class ProfileSearchForm(forms.ModelForm):
specialties = forms.ModelMultipleChoiceField(queryset=Specialty.objects.all(), widget=forms.CheckboxSelectMultiple, required=False)
class Meta:
model = Profile
fields = ('specialties',)
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
super(ProfileSearchForm, self).__init__(*args, **kwargs)
self.fields['specialties'].initial = self.request.GET.getlist('specialties')
views.py
:
from django.views.generic import ListView
from django.views.generic.edit import FormMixin
from django.core.urlresolvers import reverse_lazy
from .profiles.models import Profile
from .forms import ProfileSearchForm
class IndexView(FormMixin, ListView):
model = Profile
template_name = 'index.html'
form_class = ProfileSearchForm
success_url = reverse_lazy('index')
def get_queryset(self):
queryset = super(IndexView, self).get_queryset()
specialties = self.request.GET.getlist('specialties')
if specialties:
queryset = queryset.filter(specialties__in=specialties).distinct('user')
return queryset
def get_form_kwargs(self):
kwargs = super(IndexView, self).get_form_kwargs()
kwargs['request'] = self.request
return kwargs
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
form_class = self.get_form_class()
context['form'] = self.get_form(form_class)
return context
我认为您正在寻找Profile.objects.filter(specialties__in=specialty)
-概要文件没有专业字段,它有一个专业字段。
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.