Django-filter: OR рд╢рд░реНрдд рдХреЗ рд╕рд╛рде рдХрдИ рдлрд╝реАрд▓реНрдб рдкрд░ рдлрд╝рд┐рд▓реНрдЯрд░ рдХрд░реЗрдВ

рдХреЛ рдирд┐рд░реНрдорд┐рдд 13 рдЕрдХреНрддреВре░ 2019  ┬╖  8рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: carltongibson/django-filter

рдирдорд╕реНрддреЗ,
OR рдХрдВрдбреАрд╢рди рдХреЗ рд╕рд╛рде рдХрдИ рдлрд╝реАрд▓реНрдб рдкрд░ рдлрд╝рд┐рд▓реНрдЯрд░ рдХрд░рдирд╛ рдХрд┐рддрдирд╛ рд╕рдВрднрд╡ рд╣реИ !?
рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП:
first_name = foo OR last_name = bar
рдХреЗ рдмрд░рд╛рдмрд░:
model.objects.filter(Q(first_name=foo) | Q(last_name=bar))

рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА

рдореИрдВрдиреЗ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХреА рддрд░рд╣ рдХреБрдЫ рдХрд┐рдпрд╛ рд╣реИ, рдореБрдЭреЗ рдпрдХреАрди рдирд╣реАрдВ рд╣реИ рдХрд┐ рд╕рднреА рдорд╛рдорд▓реЛрдВ рдХреЗ рд▓рд┐рдП рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рд▓реЗрдХрд┐рди рдореЗрд░реА рд╕рдорд╕реНрдпрд╛ рд╣рд▓ рд╣реЛ рдЧрдИ рд╣реИ:

class BaseFilter(django_filters.FilterSet):
    def OR(self, queryset, field_name, value):
        if not hasattr(self, "groups"):
            setattr(self, "groups", {})

        self.groups[field_name] = value
        return queryset

    <strong i="6">@property</strong>
    def qs(self):
        base_queryset = super().qs

        if not hasattr(self, "groups"):
            return base_queryset

        query = Q()
        for key, value in self.groups.items():
            query |= Q(**{key: value})

        return base_queryset.filter(query)
class PlanFilter(BaseFilter):
    double_visit__or = django_filters.UUIDFilter("double_visit", method="OR")
    visitor__or = django_filters.UUIDFilter("visitor", method="OR")
    class Meta:
        model = models.Plan
        fields = {
            "id": ["exact"],
            "date": ["exact", "gte", "lte",],
            "visitor": ["exact"],
            "doctor": ["exact"],
            "double_visit": ["exact"]
        }

рд╕рднреА 8 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

рдЗрд╕реЗ рдЦреЛрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж, рдпрд╣ рд╡рд╣реА рдкреНрд░рд╢реНрди рд╣реИ рдЬреЛ рдореЗрд░реЗ рдкрд╛рд╕ рд╣реИред

рд╡рд░реНрддрдорд╛рди рдореЗрдВ, рдореБрдЭреЗ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЪреЗрддрд╛рд╡рдиреА рдорд┐рд▓ рд░рд╣реА рд╣реИ:

/usr/local/lib/python3.7/site-packages/django_filters/rest_framework/backends.py:128: 
UserWarning: <class 'project.api.views.FooBarViewSet'> is not compatible with schema generation

рдФрд░ рдореЗрд░реЗ рдкрд╛рд╕ рдПрдХ рдлрд╝рд┐рд▓реНрдЯрд░рд╕реЗрдЯ рдФрд░ рд╡реНрдпреВрд╕реЗрдЯ рд╣реИ рдЬреЛ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:

# models
class FooBarUserAssignment(models.Model):
    user = models.ForeignKey("auth.User", on_delete=models.CASCADE)
    foobar = models.ForeignKey("FooBar", on_delete=models.CASCADE)

    class Meta:
        unique_together = (
            ("user", "foobar"),
        )


class FooBarGroupAssignment(models.Model):
    group = models.ForeignKey("auth.Group", on_delete=models.CASCADE)
    foobar = models.ForeignKey("FooBar", on_delete=models.CASCADE)

    class Meta:
        unique_together = (
            ("group", "foobar"),
        )

class FooBar(models.Model):
    title = models.CharField(max_length=160, unique=True)

    users = models.ManyToManyField(
        to="auth.User",
        through=FooBarUserAssignment,
    )
    groups = models.ManyToManyField(
        to="auth.Group",
        through=FooBarGroupAssignment,
    )

    def __str__(self):
        return self.title

# filters
from django_filters import rest_framework as rest_framework_filters

class FooBarFilter(rest_framework_filters.FilterSet):
    title = rest_framework_filters.CharFilter(field_name="title", lookup_expr="icontains")

    class Meta:
        model = FooBar
        fields = ("title", )

# viewsets
class FooBarViewSet(ModelViewSet):
    queryset = Foobar.objects.order_by("-title")
    serializer_class = FooBarSerializer
    filterset_class = FooBarFilter

    def get_queryset(self):
        queryset = self.queryset

        q_name = Q()
        rel_name = self.request.query_params.get("rel_name", None)
        if rel_name:
            q_name = Q(users__name=rel_name)

        q_groups = Q()
        rel_groups = self.request.query_params.get("rel_groups", "").split(",")
        if any(rel_groups):
            q_groups = Q(groups__name__in=rel_groups)

        qs = queryset.filter(q_name | q_groups).distinct()
        return qs

рдореИрдВ рдареАрдХ рдЙрд╕реА рдХреНрд╡реЗрд░реА рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдлрд╝рд┐рд▓реНрдЯрд░рд╕реЗрдЯ рдХреИрд╕реЗ рдмрдирд╛ рд╕рдХрддрд╛ рд╣реВрдВ?
рдореИрдВ рдлрд╝рд┐рд▓реНрдЯрд░рд╕реЗрдЯ рдХреЗ рд╣рд┐рд╕реНрд╕реЗ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рдерд╛, рд▓реЗрдХрд┐рди рдлрд┐рд░ рднреА рдпрд╣ рдирд╣реАрдВ рдкрддрд╛ рдХрд┐ OR рддрд░реНрдХ рдХреЛ ViewSet.get_queryset() рд╕реЗ FilterSet рддрдХ рд▓реЗ рдЬрд╛рдиреЗ рдХрд╛ рд╕рдмрд╕реЗ рдЕрдЪреНрдЫрд╛ рддрд░реАрдХрд╛ рдХреНрдпрд╛ рд╣реИ

import django_filters
from django_filters import rest_framework as rest_framework_filters

class CharInFilter(django_filters.BaseInFilter, rest_framework_filters.CharFilter):
    pass

class FooBarFilter(rest_framework_filters.FilterSet):
    title = rest_framework_filters.CharFilter(field_name="title", lookup_expr="icontains")
    rel_name = rest_framework_filters.CharFilter(field_name="users__name", lookup_expr="exact")
    rel_groups = CharInFilter(field_name="groups__name")

    class Meta:
        model = FooBar
        fields = ("title", )

    def filter_queryset(self, queryset):
        qs = super().filter_queryset(queryset)
        return qs.distinct()

рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ django-filter рдХреЗ рдЗрд╕ рд╡рд┐рд╕реНрддрд╛рд░ рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рд╣реИ рдЬрд┐рд╕реЗ django-filter рдХреЗ рд╕рд╛рде рд╕реНрдерд╛рдкрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред https://github.com/philipn/django-rest-framework-filters#complex -operations

рдирдорд╕реНрддреЗред рдореИрдВрдиреЗ #1167 рдмрдирд╛рдпрд╛ рд╣реИ, рдЬреЛ рд╕рдореВрд╣-рд╕реНрддрд░реАрдп рд╕рддреНрдпрд╛рдкрди рдФрд░ рдлрд╝рд┐рд▓реНрдЯрд░рд┐рдВрдЧ рдкреНрд░рджрд╛рди рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред рдУрдкреА рдХреЗ рд▓рд┐рдП, рдЙрдкрдпреЛрдЧ рдХреБрдЫ рдРрд╕рд╛ рджрд┐рдЦрд╛рдИ рджреЗрдЧрд╛:

class UserFilter(FilterSet):
    class Meta:
        model = User
        field = ['username', 'first_name', 'last_name']
        groups = [
            CombinedGroup(filters=['first_name', 'last_name'], combine=operator.or_),
        ]

рдкреАрдЖрд░ рдкрд░ рдХрд┐рд╕реА рднреА рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреА рдмрд╣реБрдд рд╕рд░рд╛рд╣рдирд╛ рдХреА рдЬрд╛рдПрдЧреАред

рдпрд╣рд╛рдБ рдЕрднреА рднреА рд╡рд╣реА рд╕рдорд╕реНрдпрд╛ рд╣реИ, рдХреНрдпрд╛ рдЙрдирдХрд╛ рдХреЛрдИ рд╕рдорд╛рдзрд╛рди рдЕрднреА рддрдХ рд╣реИ?

@ JeromeK13 рдХреБрдЫ рднреА рдирд╣реАрдВ рдЬреИрд╕рд╛ рджрд┐рдЦрддрд╛ рд╣реИ! рдореЗрд░рд╛ рдПрдХ рд╣реА рд╕рд╡рд╛рд▓ рд╣реИ

рдореИрдВрдиреЗ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХреА рддрд░рд╣ рдХреБрдЫ рдХрд┐рдпрд╛ рд╣реИ, рдореБрдЭреЗ рдпрдХреАрди рдирд╣реАрдВ рд╣реИ рдХрд┐ рд╕рднреА рдорд╛рдорд▓реЛрдВ рдХреЗ рд▓рд┐рдП рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рд▓реЗрдХрд┐рди рдореЗрд░реА рд╕рдорд╕реНрдпрд╛ рд╣рд▓ рд╣реЛ рдЧрдИ рд╣реИ:

class BaseFilter(django_filters.FilterSet):
    def OR(self, queryset, field_name, value):
        if not hasattr(self, "groups"):
            setattr(self, "groups", {})

        self.groups[field_name] = value
        return queryset

    <strong i="6">@property</strong>
    def qs(self):
        base_queryset = super().qs

        if not hasattr(self, "groups"):
            return base_queryset

        query = Q()
        for key, value in self.groups.items():
            query |= Q(**{key: value})

        return base_queryset.filter(query)
class PlanFilter(BaseFilter):
    double_visit__or = django_filters.UUIDFilter("double_visit", method="OR")
    visitor__or = django_filters.UUIDFilter("visitor", method="OR")
    class Meta:
        model = models.Plan
        fields = {
            "id": ["exact"],
            "date": ["exact", "gte", "lte",],
            "visitor": ["exact"],
            "doctor": ["exact"],
            "double_visit": ["exact"]
        }

рдореЗрд░рд╛ рдорд╛рдирдирд╛ тАЛтАЛтАЛтАЛрд╣реИ рдХрд┐ рдореБрдЭреЗ рдмрд╣реБрдд рдЖрд╕рд╛рди рддрд░реАрдХрд╛ рдорд┐рд▓рд╛ рд╣реИ:

from django.db.models.query_utils import Q
user_contacts = Contact.objects.order_by('-contact_date').filter(Q(sender_id=request.user.user_id)|Q(receiver_id=request.user.user_id)) 

рдореЗрд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдореИрдВ рдЙрди рд╕рднреА рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рдЗрдХрдЯреНрдард╛ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛ рдЬрд╣рд╛рдВ рд╡рд┐рд╢рд┐рд╖реНрдЯ sender_id рдпрд╛ receiver_id рд╣реИред рдФрд░, рдореИрдВ рдЪрд╛рд╣рддрд╛ рдерд╛ рдХрд┐ рд╡реЗ date . рджреНрд╡рд╛рд░рд╛ рдСрд░реНрдбрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдХреНрд╡реЗрд░реА рд╕реЗрдЯ рдореЗрдВ рд╣реЛрдВ

рдирдорд╕реНрддреЗ,
OR рдХрдВрдбреАрд╢рди рдХреЗ рд╕рд╛рде рдХрдИ рдлрд╝реАрд▓реНрдб рдкрд░ рдлрд╝рд┐рд▓реНрдЯрд░ рдХрд░рдирд╛ рдХрд┐рддрдирд╛ рд╕рдВрднрд╡ рд╣реИ !?
рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП:
first_name = foo OR last_name = bar
рдХреЗ рдмрд░рд╛рдмрд░:
model.objects.filter(Q(first_name=foo) | Q(last_name=bar))

рдЖрдпрд╛рдд рдХреНрдпреВ

django.db.models рдЖрдпрд╛рдд Q

рдЗрд╕рдиреЗ рдореЗрд░реЗ рд▓рд┐рдП рдХрд╛рдо рдХрд┐рдпрд╛ред

рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕

рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ

csarcom picture csarcom  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

sassanh picture sassanh  ┬╖  4рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

madelyneriksen picture madelyneriksen  ┬╖  4рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

jnegro picture jnegro  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

ses4j picture ses4j  ┬╖  4рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ