5 ms·
The Django filter syntax with the double underscores is like fingernails on a chalkboard to me. I find it insane that they didn't just use operator overloading
by BrenBarn 3mo ago
The Django filter syntax with the double underscores is like fingernails on a chalkboard to me. I find it insane that they didn't just use operator overloading to create a real query expression language.
- ezst 3mo agoOr now that python has ~types, this is really an area where things could be improved. Filtering would just be lambda predicate with fields auto complete as seen in .NET, scala, etc
- 7bit 3mo agoThere may be many reason other than rejecting that suggestion leading to what it is know. Your statement somehow suggests that it was deliberately decided against what you propose. I don't think we know that. I can't quite picture how operator overloading would look like, could you give an example?
- echoangle 3mo ago> I can't quite picture how operator overloading would look like, could you give an example? Instead of this: self.filter(end__gt=self._midnight(today)) You could write a "Field" class that implements __getattr__ and __gt__ so you could do self.filter(Field.end > self._midnight(today)) The "Field.end > self._midnight(today)" would evaluate to an object that would just store "my field name is end and my value needs to be larger than xyz". filter() can then look into its argument list and construct the filter criteria from the passed Field objects instead of the key value pairs as it does now.
- pbalau 3mo agoif 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 3mo 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 3mo agoIf you change an operation that is meant to return a Boolean to return anything else, you are insta fired.
- 3mo ago
- mmclar 3mo agoSQLalchemy does that. One advantage of the Django syntax is that it can be (pretty much) directly dropped into a query string on any admin page or DRF query and filter the results. E.g. the admin page for all the events after noon today: admin/event/?end__gt=2026-07-26T12:00:00 Being able to do ad-hoc queries using the same paradigm your app queries are written in, and then pass urls around with those queries included (e.g., quick one-off reports or answers to client questions) is so helpful.
- ptx 3mo agoThis convenience sounds a little dangerous. Would this allow the user to specify e.g. joins or SQL procedure calls using the query parameter?
- zbentley 2mo agoIf you mean “would it allow arbitrary queries in the admin interface?”, then yes, it would. That’s why it’s the admin interface. If you mean “would it allow arbitrary queries from normal view code”, then no it would not—not unless you string eval on the backend or something else dangerous.
- woadwarrior01 3mo agoYou might want to look at Peewee's query filtering syntax. https://docs.peewee-orm.com/en/latest/peewee/querying.html#filtering https://docs.peewee-orm.com/en/latest/peewee/querying.html#f...
- BrenBarn 3mo agoI have, yeah. That's kind of my point: other ORMs do this better than Django.
- mixmastamyk 3mo agoI think you can do that with querysets, Q, and F. The kwargs are a limited convenience.