【问题标题】:How to filter based on previous queryset results Django如何根据以前的查询集结果进行过滤 Django
【发布时间】:2019-07-12 01:11:10
【问题描述】:

目前,我有 2 个独立的查询集在同一页面上相互独立呈现。

Q1=users

Q2=f

Q1 返回用户发布范围内的所有用户 (request.POST)。

Q2 根据选择的过滤器(头发颜色、年龄等)返回django_filters.FilterSet (request.GET)

Q2 应该只过滤Q1 的结果。我想把它全部放在同一个页面上,而不是重定向到不同的网址。

如果有人能解释最简单的方法,我将不胜感激。

views.py

class ConnectView(View):
    template_name = 'connect/home.html'
    def get(self, request, *args, **kwargs):
        filter = ProfileFilter(request.GET.getlist('filter'))
        context = {
            'users': User.objects.exclude(username=request.user),
            'filter': filter
        }
        return render(request, self.template_name, context)

    def post(self, request, *args, **kwargs):
        if 'latitude' in request.POST and 'longitude' in request.POST:
            try:
                location = Location(latitude=request.POST['latitude'], longitude=request.POST['longitude'], user = request.user)
                location.save()
            except:
                return JsonResponse({'message': 'location already stored!'})

        if 'radius' in request.POST:
            radius_km = request.POST.get('radius', 0)
            queryset = User.objects.annotate(
                radius_sqr=pow(models.F('loc__latitude') -
                request.user.loc.latitude, 2) + pow(models.F('loc__longitude') -
                request.user.loc.longitude, 2)
                ).filter(
                radius_sqr__lte=pow(int(radius_km) / 9, 2)
                ).exclude(username=request.user)
            filter = ProfileFilter(request.POST, queryset=queryset)
            messages.success(request, f'See the results of your search below.')
            return render(request, self.template_name)

        else:
            return render(request, self.template_name)

filters.py

class ProfileFilter(django_filters.FilterSet):
    class Meta:
        model = Profile
        fields = {
            'age': ['exact'],
            'interest': ['exact'],
        }

connecthome.html

  <form method="POST">
    {% csrf_token %}
    <h4>Enter a Distance.</h4>
    <input type="number" name="radius">
    {{ filter.form|crispy }}
    <button type="submit">Search.</button>
  </form>

    {% if filter %}
        {% for profile in filter %}
            <h5>{{ profile.user.first_name }}</h5>
            <p>{{ profile.age }}</p>
        {% empty %}
            <h1>No results, try again?</h1>
        {% endfor %}
    {% else %}
        {% for user in users %}
            <h5>{{ user.first_name }}</h5>
            <p>{{ user.profile.age }}</p>
        {% empty %}
            <h1>No results, try again?</h1>
        {% endfor %}
    {% endif %}

【问题讨论】:

  • 页面是作为 GET 请求或 POST 请求的结果返回的,不能同时是两者。将所有内容放在一个表单中并使用 GET 或 POST 提交所有信息(过滤器选择和距离)。可能 GET 更合适,因为您没有向数据库写入任何内容。
  • 是的,我确实查过了,发现我无法合并这两个请求..好的,谢谢你的帮助,我真的很感激。我如何在forms.py 中组合filters.py django_filtersradius 查询集?
  • 将半径查询集从您的POST 方法传递到您的过滤器,您可以从request.GET 而不是request.POST 获得radius
  • 所以你说可以将radius 查询集传递给filters.py,然后它会渲染出一个FilterSet 并由request.GET 处理(就像当前的其他过滤器信息一样) ?你介意告诉我将半径查询集传递给filters.py 会是什么样子吗?
  • 我的意思是将您现在在 post() 中拥有的代码移动到您的 get() 方法中(并完全删除 post(),抱歉,我的评论中并不清楚。所以首先你检查对于radius,根据radius 是否在request.GET 中构建您的查询集,然后使用该查询集使用过滤器过滤您的用户。

标签: django django-views django-filter


【解决方案1】:

您应该将您的模板更改为只有一个表单可以同时发布半径和过滤器。然后在您的 post 方法中,使用位置/半径来创建您传递给过滤器的查询集:

def post(self, request, *args, **kwargs):
    # default queryset, users is needed in context based on your get() method
    users = User.objects.exclude(username=request.user.username)
    queryset = Profile.objects.exclude(user=request.user)  
    if 'latitude' in request.POST and 'longitude' in request.POST:
        # code to store Location

    if 'radius' in request.POST:
        radius_km = request.POST.get('radius', 0)
        # reduce queryset by users within radius
        queryset = queryset.annotate(
            radius_sqr=pow(models.F('user__loc__latitude') -
            request.user.loc.latitude, 2) + pow(models.F('user__loc__longitude') -
            request.user.loc.longitude, 2)
            ).filter(
            radius_sqr__lte=pow(int(radius_km) / 9, 2)
            )
        messages.success(request, f'See the results of your search below.')

    filter = ProfileFilter(request.POST, queryset=queryset)
    return render(request, self.template_name, {'filter': filter, 'users': users})

【讨论】:

  • 好的最后一个问题,当前用户并没有被排除在结果之外,即使是.exclude(username=request.user),为什么需要这条线?
  • 如果我在get方法中有{'filter': f}
  • 在 get() 中,您在我的 post() 中将变量称为 f,我将其称为 filter(我从不使用像 f 这样的变量名称,因为它们没有任何意义)。没关系。
  • 抱歉这里有些地方不正确,传递给ProfileFilter 的查询集应该在Profile 对象上。 ProfileUser 有什么关系?
  • 对不起,我的意思是整行queryset = users = User.objects.exclude(username=request.user)
猜你喜欢
  • 1970-01-01
  • 2013-04-20
  • 2022-07-19
  • 2018-11-03
  • 2013-09-29
  • 1970-01-01
  • 2015-05-10
  • 2019-10-08
  • 1970-01-01
相关资源
最近更新 更多