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))
This gives: {'field': 'end', 'operator': '>', 'value': datetime.datetime(2024, 1, 1, 0, 0)}
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)))
This printsend__gt = 2024-01-01 00:00:00
If you change an operation that is meant to return a Boolean to return anything else, you are insta fired.
I would have agreed with this, and then they did the `pathlib.Path` bit of cuteness with the `/` operator: https://github.com/python/cpython/blob/5afbb60e0283caaf34990...
And despite my misgivings, it’s really ergonomic.
If you divide a Path by another Path, you get a Path. If you compare two Paths, you get a Boolean. It is not really the same.
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.
You mean like the numpy authors that let the comparison operators return arrays?
Also, apparently SQLAlchemy does exactly what I proposed so apparently they are erring in their ways too.
I honestly don’t find it that bad.