I am making a tutoring dashboard in Django. The tools used are htmx,jquery, bootstrap.
In the tutors.html page, there is a searchbar. When an user types something, it will send a request to the server and it would call the view search_tutor. The following is the code:
<form method="POST">
{% csrf_token %}
<div class="form-floating mb-3">
<input class="form-control" id="search-input" hx-get="{% url 'search_tutor' %}" hx-target="#tutors" hx-trigger="keyup changed" name="q" placeholder="Search Tutor" data-sb-validations="required">
<label class="text-muted" for="q"> Search Tutor</label>
</div>
</form>
<div id="tutors" style="transition:1s">
{% include "templates/partials/tutors.html" %}
</div>
The Tutor Model is the following:
class Account(models.Model):
token = models.CharField(max_length=50, unique=True)
user = models.OneToOneField(User, on_delete=models.CASCADE)
profile_picture = models.ImageField(upload_to=upload_prof_pic, blank=True, null=True)
school = models.ForeignKey(School, on_delete=models.CASCADE , null=True)
country = models.ForeignKey(Country, on_delete=models.DO_NOTHING, related_name='account_country', null=True)
phone = models.CharField(max_length=20, blank=False)
added = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
stripe_account = models.CharField(max_length=300, blank=True)
stripe_client = models.CharField(max_length=300, blank=True)
is_tutor = models.BooleanField(default=False)
description = models.TextField(max_length=600, blank=False)
tutor_subject = models.ManyToManyField(Subject, blank=True, null=True )
def __str__(self):
return str(self.user)
def get_phone(self, *args, **kwargs):
if self.country != None:
return f"+{self.country.phone_extension} ({self.phone1})-{self.phone2}-{self.phone3}"
else:
return "NONE"
def rating_score (self, *args, **kwargs):
total = 0
amount = 0
r = Rating.objects.filter(user=self.user)
if r.count() == 0 :
return 0
else:
for i in r.all():
total += i.rating
amount +=1
return total/amount
def rating_count(self, *args, **kwargs):
r = Rating.objects.filter(user=self.user)
return r.count()
def full_name(self, *args, **kwargs):
return f'{self.user.first_name.title()} {self.user.last_name.title()}'
I think my problem could be in the filter on the view. I do not know what is happening, but when I type something in the searchbar, multiple copies of the same object appear. Here is my search_tutor view:
def search_tutor(request):
x = Account.objects.get(user=request.user)
if request.method == "GET":
q = request.GET['q']
a= Account.objects.filter(
Q(is_tutor=True)
&(
Q(user__first_name__icontains=q)|
Q(user__last_name__icontains=q)|
Q(user__email__icontains=q)|
Q(tutor_subject__name__icontains=q)|
Q(tutor_subject__abbr__icontains=q)|
Q(user__username__icontains=q)|
Q(description__icontains=q)
)
)
context= {'a': a}
return render(request, f"{mp}/tutors.html", context)
Here are images: When the page opens, it shows the right amount of users. When I start typing, more than on of the same item is returned
Any help would be greatly appreciated.
I tried doing some searches but it seems that I am the only one.
That is the result of filtering on one-to-many and many-to-many relations where there are multiple matches in the related models.
You can use
.distinct()
to return each item at most once: