Skip to content
Snippets Groups Projects
fields.py 3.49 KiB
Newer Older
  • Learn to ignore specific revisions
  • import django_filters
    
    from django import forms
    
    from django.core.serializers.json import DjangoJSONEncoder
    
    from django.db import models
    
    
    from rest_framework import serializers
    
    
    Eliot Berriot's avatar
    Eliot Berriot committed
    from . import search
    
    PRIVACY_LEVEL_CHOICES = [
    
    Eliot Berriot's avatar
    Eliot Berriot committed
        ("me", "Only me"),
        ("followers", "Me and my followers"),
        ("instance", "Everyone on my instance, and my followers"),
        ("everyone", "Everyone, including people on other instances"),
    
    ]
    
    
    def get_privacy_field():
        return models.CharField(
    
    Eliot Berriot's avatar
    Eliot Berriot committed
            max_length=30, choices=PRIVACY_LEVEL_CHOICES, default="instance"
        )
    
    def privacy_level_query(user, lookup_field="privacy_level", user_field="user"):
    
        if user.is_anonymous:
    
    Eliot Berriot's avatar
    Eliot Berriot committed
            return models.Q(**{lookup_field: "everyone"})
    
    Eliot Berriot's avatar
    Eliot Berriot committed
        return models.Q(
    
            **{"{}__in".format(lookup_field): ["instance", "everyone"]}
        ) | models.Q(**{lookup_field: "me", user_field: user})
    
    
    
    class SearchFilter(django_filters.CharFilter):
        def __init__(self, *args, **kwargs):
    
    Eliot Berriot's avatar
    Eliot Berriot committed
            self.search_fields = kwargs.pop("search_fields")
    
            super().__init__(*args, **kwargs)
    
        def filter(self, qs, value):
            if not value:
                return qs
    
    Eliot Berriot's avatar
    Eliot Berriot committed
            query = search.get_query(value, self.search_fields)
    
            return qs.filter(query)
    
    Eliot Berriot's avatar
    Eliot Berriot committed
    
    
    class SmartSearchFilter(django_filters.CharFilter):
        def __init__(self, *args, **kwargs):
            self.config = kwargs.pop("config")
            super().__init__(*args, **kwargs)
    
        def filter(self, qs, value):
            if not value:
                return qs
    
            try:
                cleaned = self.config.clean(value)
    
            except (forms.ValidationError):
    
                return qs.none()
    
    Eliot Berriot's avatar
    Eliot Berriot committed
            return search.apply(qs, cleaned)
    
    
    
    class GenericRelation(serializers.JSONField):
        def __init__(self, choices, *args, **kwargs):
            self.choices = choices
            self.encoder = kwargs.setdefault("encoder", DjangoJSONEncoder)
            super().__init__(*args, **kwargs)
    
        def to_representation(self, value):
            if not value:
                return
            type = None
            id = None
            for key, choice in self.choices.items():
                if isinstance(value, choice["queryset"].model):
                    type = key
                    id = getattr(value, choice.get("id_attr", "id"))
                    break
    
            if type:
                return {"type": type, "id": id}
    
        def to_internal_value(self, v):
            v = super().to_internal_value(v)
    
            if not v or not isinstance(v, dict):
                raise serializers.ValidationError("Invalid data")
    
            try:
                type = v["type"]
                field = serializers.ChoiceField(choices=list(self.choices.keys()))
                type = field.to_internal_value(type)
            except (TypeError, KeyError, serializers.ValidationError):
                raise serializers.ValidationError("Invalid type")
    
            conf = self.choices[type]
            id_attr = conf.get("id_attr", "id")
            id_field = conf.get("id_field", serializers.IntegerField(min_value=1))
            queryset = conf["queryset"]
            try:
                id_value = v[id_attr]
                id_value = id_field.to_internal_value(id_value)
            except (TypeError, KeyError, serializers.ValidationError):
                raise serializers.ValidationError("Invalid {}".format(id_attr))
    
            query_getter = conf.get(
                "get_query", lambda attr, value: models.Q(**{attr: value})
            )
            query = query_getter(id_attr, id_value)
            try:
                obj = queryset.get(query)
            except queryset.model.DoesNotExist:
                raise serializers.ValidationError("Object not found")
    
            return obj