3 ms·
if self._midnight(today) returns a datetime object, than: self.filter(end__gt=self._midnight(today)) will evaluate to: self.filter(end__gt=<some_dateti
by pbalau 2mo ago
if self._midnight(today) returns a datetime object, than:
self.filter(end__gt=self._midnight(today))
will evaluate to:
self.filter(end__gt=<some_datetime_object>)
While
self.filter(Field.end > self._midnight(today))
will evaluate to:
self.filter(<True/False>)
- echoangle 2mo agoNot 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 prints end__gt = 2024-01-01 00:00:00
- pbalau 2mo agoIf you change an operation that is meant to return a Boolean to return anything else, you are insta fired.
- echoangle 2mo agoYou 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.
- vtbassmatt 2mo agoI would have agreed with this, and then they did the `pathlib.Path` bit of cuteness with the `/` operator: https://github.com/python/cpython/blob/5afbb60e0283caaf34990bbe8437111ebaae04a4/Lib/pathlib/__init__.py#L175 https://github.com/python/cpython/blob/5afbb60e0283caaf34990... And despite my misgivings, it’s really ergonomic.
- pbalau 2mo agoIf 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.
- BrenBarn 2mo agoThat'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.
- zzzeek 2mo agoHi, don't mind me, but You don't need to return a boolean. You need to return an object that implements __bool__. Get it ? And even then, when you're dealing with objects that are special to expressions, you don't actually even need __bool__ that much
- 7bit 2mo agoHow would you model string comparisons with LIKE?
- BrenBarn 2mo agoFor those you would have a method on the field object (e.g., `Table.field.like("whatever")`).
- 7bit 2mo agoYeah, 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.
- BrenBarn 2mo agoNot 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.
- BrenBarn 2mo agoNo 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.