簡體   English   中英

如何在Django中的“多對多”字段中搜索?

[英]How to search on a Many to Many field in Django?

我有一個Profile模型,在另一個模型Specialty上具有ManyToManyField

我想對Profile模型進行簡單的搜索以找到特長並返回匹配的Profile。 就目前而言,我的表單可以正確顯示在模板中,但是提交后我什么也收不到。

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>

我覺得這與self.profile_list 我不知道是否/如何將它放入get_extra_context 它在第一次訪問時就不存在,所以我不知道如何使其存在或傳遞它。 我也不確定Profile.objects.filter(specialty__in=specialty)是否是在多對多字段上進行字段查找的正確方法。

如果有優勢,我也歡迎其他搜索建議(例如Haystack)。 我更喜歡一組復選框,我認為Haystack無法通過構面來處理。

感謝Gergo和Cameron。 我現在把它修好了。 您對這個問題是正確的,但是還有很多步驟要走。

  • 我真正想要的是一個ListView加做一個簡單的搜索,這應該是一個能力FormMixin ,讓我補充form_classsuccess_url ,而不是把它們當作一個FormView
  • 當在ListView指定默認model ,視圖會吹走上下文,因此form永遠不會到達模板。 get_context_data需要將表單添加回上下文中,文檔中有一個example
  • 應該刪除form_valid因為搜索絕不是POST請求,盡管文檔在FormMixin的“注釋”下說了要求form_validform_invalid
  • 我需要get_queryset來通過model獲取默認的查詢集,或者讀取GET請求的specialties值並適當地過濾結果。
  • 為了獲得獎勵積分, get_form_kwargs需要將當前請求傳遞給表單,以便在頁面刷新后仍可以保留初始表單值。 棘手的部分是,當使用ModelMultipleChoiceField ,必須使用request.GETgetlist而不是get方法來讀取該值列表。

現在都在一起了...

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) -概要文件沒有專業字段,它有一個專業字段。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM