ALLOWED_OPERATOR = ["gt", "gte", "le", "lte"]
OPERATOR_MAP = {
"gt": "__gt__",
"gte": "__ge__",
"lt": "__lt__",
"lte": "__le__",
}
class Compare(R):
"""
Django-like query for comparison :
- `Compare(field__gt=3)`
- `Compare(field__gte=3)`
- `Compare(field__lt=3)`
- `Compare(field__gte=3)`
"""
def __repr__(self):
return "R({})".format(
", ".join("{}__{}={!r}".format(*k.rsplit("__", 1), v) for k, v in self.kwargs.items())
)
def check(self, user, instance=None):
if instance is None:
return False
# This loop exits early, returning False, if any argument
# doesn't match.
for key, value in self.kwargs.items():
# Find the appropriate LHS on this object, traversing
# foreign keys if necessary.
lhs = instance
key, operator = key.rsplit("__", 1)
if operator not in ALLOWED_OPERATOR:
raise NotImplementedError("Operator must be in %s" % ALLOWED_OPERATOR)
for key_fragment in key.split("__"):
field = lhs.__class__._meta.get_field(
key_fragment,
)
if isinstance(field, ForeignObjectRel):
attr = field.get_accessor_name()
else:
attr = key_fragment
lhs = getattr(lhs, attr)
# Compare it against the RHS.
# Note that the LHS will usually be a value, but in the case
# of a ManyToMany or the 'other side' of a ForeignKey it
# will be a RelatedManager. In this case, we need to check
# if there is at least one model that matches the RHS.
if isinstance(value, Rule):
raise NotImplementedError("value can not be a Rule")
# if isinstance(value, Rule):
# if isinstance(lhs, Manager):
# if not value.filter(user, lhs.all()).exists():
# return False
# else:
# if not value.check(user, lhs):
# return False
# else:
resolved_value = value(user) if callable(value) else value
if isinstance(lhs, Manager):
raise NotImplementedError("lhs cannot be a Manager")
# if resolved_value not in lhs.all():
# return False
else:
if not getattr(lhs, OPERATOR_MAP[operator])(resolved_value):
return False
# Woohoo, everything matches!
return True
Hello!
It would be nice to have comparison and not strict equality between lhs and value. For now, we can do:
but we can not do
and that would be terrific!
This would allow stuff like:
Are you interested in a PR?
The PR would look like this (adapted from
R
):