Множественный поиск с внешним ключом django (Related Field got invalid lookup: icontains)

Я понимаю, что нельзя напрямую использовать иконки на внешнем ключе при поиске, но пока не нашел решения.

Вот мое представление поиска в файле views.py (я импортировал все необходимые модели):

def search(request):
    # if the user actually fills up the form
    if request.method == "POST":
        searched = request.POST['searched']
        # author__icontains part is not working
        posts = Post.objects.filter(Q(title__icontains=searched) | Q(author__author__icontains=searched))

        return render(request, 'blog/search.html', {'searched': searched, 'posts': posts})
    else:
        return render(request, 'blog/search.html', {})

Вот моя модель в model.py:


class Post(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    date_posted = models.DateTimeField(default=timezone.now)
    author = models.ForeignKey(User, on_delete=models.CASCADE)

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('post-detail', kwargs={'pk': self.pk})

В основном, это не работает:

        posts = Post.objects.filter(Q(title__icontains=searched) | Q(author__author__icontains=searched))

Ошибка Related Field got invalid lookup: icontains

author is a User object. Therefore you should work with username, or first_name, or some other field. Likely author is also the value of a related_name=… [Django-doc] that thus makes a LEFT OUTER JOIN on another table, and thus would work on the primary key(s) of that table.

Таким образом, вы фильтруете:

def search(request):
    # if the user actually fills up the form
    if request.method == 'POST':
        searched = request.POST['searched']
        # author__icontains part is not working
        posts = Post.objects.filter(
            Q(title__icontains=searched) |
            Q(author__username__icontains=searched)
        )

        return render(request, 'blog/search.html', {'searched': searched, 'posts': posts})
    return render(request, 'blog/search.html')

Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.


Примечание: Поиск обычно выполняется через запрос GET, поскольку это означает, что запрос хранится в строке запроса и, следовательно, в URL. Это делает удобным, например, передачу URL с запросом кому-то другому или добавление результата в закладки. POST-запросы обычно используются для действий, изменяющих состояние, или для запросов с чувствительными данными.

Эта проблема вызвана неспособностью Django обрабатывать внешние ключи с несколькими значениями для одного поля. Причина этого ограничения в том, что Django не знает, как разрешить эти конфликты, поэтому просто игнорирует их. В вашем случае, поскольку в вашей модели есть два поля, которые соответствуют критериям поиска, Django проигнорирует оба результата и отобразит пустой список.

Чтобы решить эту проблему, нам нужно добавить новый атрибут в нашу модель под названием "icontains", который будет содержать значение другого поля. Затем мы установим этот атрибут в качестве значения по умолчанию для поля "author" при запросе из базы данных. Вот как теперь должна выглядеть ваша модель:

class Post(models.Model): title = models.CharField(max_length=100) content = models.TextField() date_posted = models.DateTimeField(default=timezone.now) author = models.ForeignKey(User, on_delete=models.CASCADE) icontains = models.CharField(max_length=100, null=True, blank=True) def __str__(self): return self.title def get_absolute_url(self): return reverse('post-detail', kwargs=dict(pk=self.pk))

После этого изменения код будет работать правильно.

Для получения дополнительной информации об этом ограничении смотрите документацию Django здесь: https://docs.djangoproject.com/en/1.9/topics/db/queries/#lookups-that-span-relationships

Вернуться на верх