1

Hello I want to create simple search form which will allow to get data from related models.

I have 3 models:

class Person(models.Model):
    name = models.CharField()
    surname = models.CharField()

class Phone(models.Model):
    person = models.ForeignKey(Person,on_delete=models.CASCADE,related_name="phones")
    phone = models.CharField(0

class Email(models.Model):
    person = models.ForeignKey(Person,on_delete=models.CASCADE, related_name="emails")
    email = models.EmailField()

in my home view I have:

def home(request):
    people = Person.objects.all()
    query = request.GET.get("q")
    if query:
        people = Person.objects.filter(Q(name__icontains=query)|Q(surname__icontains=query)|
                 Q(emails__contains=query)|Q(phones__icontains=query))
    //when I try emails_email__icontains=query I get error about no such fields

    return render(request,'app/home.html',{'users': people})

And it works fine, but I would like to search throug emails and phones too (person can have fews email and phone). If in my query I use another OR (|), I got error I cant combine 2 models in one query. I also wanto to try with chain:

people= above query
emails = Email.objects.filter(email__icontains=query)
context = chain(people,emails)

Unfortunately, this solution doesnt work too. How can I solve this?

EDIT: TEMPLATE

{% block content %}
   {%for user in users %}
      {{user.id }} {{user.name}} {{user.surname}}
      {% for email in user.email_set.all %}
         {{email}}
      {% endfor %}
    {% endfor %}
Frendom
  • 508
  • 6
  • 24

3 Answers3

2

you can use Q here:

models:

class Phone(models.Model):
    person = models.ForeignKey(Person,on_delete=models.CASCADE, related_name="phones")
    phone = models.CharField(0

class Email(models.Model):
    person = models.ForeignKey(Person,on_delete=models.CASCADE, related_name="emails")
    email = models.EmailField()

views:

from django.db.models import Q

def home(request):
    people= Person.objects.all()
    query - request.GET.get("q")
    if query:
        people = Person.objects.filter(Q(name__icontains=query) | Q(surname__icontains=query) | Q(emails__email__icontains=query) | Q(phones__phone__icontains=query))

    return render(request,'app/home.html',{'users': people})

use chain

katoozi
  • 388
  • 2
  • 6
1

try this

in models.py

class Person(models.Model):
    name = models.CharField()
    surname = models.CharField()

class Phone(models.Model):
    person = models.ForeignKey(Person,on_delete=models.CASCADE, related_name='a')
    phone = models.CharField(0

class Email(models.Model):
    person = models.ForeignKey(Person,on_delete=models.CASCADE, related_name='b')
    email = models.EmailField()

in filter

from django.db.models import Q

people = Person.objects.filter(Q(name__icontains=query)|Q(surname__icontains=query)|Q(b__email__icontains=query))

in template

{% block content %}
{% for user in users %}
    {{user.id }} {{user.name}} {{user.surname}}
    {% for email in user.b.all %}
       {{email.email}}
    {% endfor %}
{% endfor %}

hope it helps

rahul.m
  • 5,572
  • 3
  • 23
  • 50
  • Well, when I added related_name to my models, they aren't displayed in my html file. Before I had: {% for email in user.email_set.all %} which was working. And after changes is not. I tried {% for email in user.emails %}, but nothing is displayed – Frendom Jun 12 '19 at 11:40
  • I added my template – Frendom Jun 12 '19 at 11:47
  • so atm phones and emails are displayed. But when I want to search I get FieldErros - Related Field go invalid lookup: icontains – Frendom Jun 12 '19 at 11:57
  • @Frendom use double underscore **emails__email__icontains** – rahul.m Jun 12 '19 at 12:10
  • It works, thank you. THe only problem is if user has few emails or phones he is displayed multiple times after searching – Frendom Jun 12 '19 at 12:19
1

To what I understand of the question, you basically need a union of people having the search query either as an email or as a phone.

    Person.objects.filter(Q(mobile__icontains=query)|Q(email__icontains=query))

The above query will return the list of Person objects as a result. This is basically a reverse lookup which will search all models having Person as a foreign key and having fields namely mobile and email.