Not if you do the magic with getattr and comparison overrides.
You actually need to do it on the metaclass because the Field as I wrote it isn't an instance but this works:
from datetime import datetime
class Filter():
def __init__(self, name):
self.name = name
def __gt__(self, value):
return {
"field": self.name,
"operator": ">",
"value": value
}
class FieldMeta(type):
def __getattr__(cls, name):
return Filter(name)
class Field(metaclass=FieldMeta):
pass
print(Field.end > datetime(2024, 1, 1))
You can make python return arbitrary values for comparisons by overriding __gt__ (and lt, eq) on the first operand (which we control here since it is a Field class), it doesn't have to be a bool.
Edit:
You can even make a little adapter to use this with the current filter system if you really want to:
from datetime import datetime
class Filter():
def __init__(self, name):
self.name = name
def __gt__(self, value):
return {
"field": self.name,
"operator": "gt",
"value": value
}
def __lt__(self, value):
return {
"field": self.name,
"operator": "lt",
"value": value
}
def __eq__(self, value):
return {
"field": self.name,
"operator": "eq",
"value": value
}
class FieldMeta(type):
def __getattr__(cls, name):
return Filter(name)
class Field(metaclass=FieldMeta):
pass
def _(*args):
kwargs = {}
for arg in args:
k = arg["field"] + "__" + arg["operator"]
kwargs[k] = arg["value"]
return kwargs
def filter(**kwargs):
for k, v in kwargs.items():
print(f"{k} = {v}")
filter(**_(Field.end > datetime(2024, 1, 1)))
That's a well established pattern in Python, for instance with Numpy. That's the point. Operations in Python aren't "mean to return" anything in particular. Each class can define the operations as it wants. That's a powerful feature that allows creation of specialized expression languages, as used by other ORMs besides Django.
No it won't, because there's no requirement that the result of `>` be True or False. It can return an object that then can participate in further expressions that "keep track" of what operations are done to the fields.
Yeah, but that's different from the operator. It's a different way of thinking about it. Maybe that's the reason they used dou le underscores for everything, to keep it consistent.
Not really. Both method calls and operators are consistent with how Python normally works. Outside of Django you never do `obj__op(value)` or `obj__meth(value)` to do the equivalent of `obj op value` or `obj.meth(value)`. It is Django that is inconsistent with how operations are done in Python.