Idea: Allow queryset.get() and queryset.filter() to accept a positional argument for implicit primary key filtering

151 views
Skip to first unread message

Antwan

unread,
Oct 31, 2018, 1:13:34 PM10/31/18
to Django developers (Contributions to Django itself)
Hi,
I'm creating this topic to see if there is interest to implement positional arguments in queryset filtering.

Current situation

Currently the only way to use positional arguments to filter can be either:

  • Passing a single or multiple Q objects:
    MyClass.objects.filter(Q(key=value))
    MyClass.objects.filter(Q(key=value), Q(other_key=value))
    
  • Passing a couple is also working (not sure if this is a happy accident, should it be removed?)
    MyClass.objects.filter((key, value))
    
  • Combination of both is also proven to work
    MyClass.objects.filter((key, value), Q(other_key=value))
    


Suggestion

This feature suggestion is to leverage the case when a non-Q / non couple object is passed, so it implicitly interpreted as the value for the model's pk.

This could ease/simplify code by omitting pk when this is the only filter used:


MyClass.objects.get(value)
# Translates into: MyClass.objects.get(pk=value)


or


MyClass.objects.filter(value)
# Translates into: MyClass.objects.filter(pk=value)


or


MyClass.objects.filter(Q(value)) # Translates into: MyClass.objects.filter(Q(pk=value))
 
Do you think it's worth it? It could be leveraged to simplify many situations.
I'd be happy to proceed to the development myself if this is something gathering interest.

charettes

unread,
Oct 31, 2018, 2:12:53 PM10/31/18
to Django developers (Contributions to Django itself)
As I've mentioned on the ticket I've been wishing get(pk) could translate
to get(pk=pk) for a while but I never got to suggest it. Probably because I
didn't feel like adding (pk=...) was really that long. I'd note that most of the
times I wished this existed was when doing some object manipulations
through a Django shell.

I'm not convinced this would be as useful for `filter()` though as I don't
recall wanting to retrieve a set of objects matching a value I know will
be unique.

Something to keep in mind as well is whether or not we want to allow
this to be coupled with extra args and kwargs.

e.g.

    Book.objects.get(isbn, author__name='Daniel Roy Greenfeld')

I'd be in favor of preventing pk and kwarg or Q args mixing.

Count me +1 for the get() case and -1 for the filter() one.

Simon

Antwan

unread,
Oct 31, 2018, 2:53:35 PM10/31/18
to Django developers (Contributions to Django itself)
I'm not convinced this would be as useful for `filter()` though as I don't
recall wanting to retrieve a set of objects matching a value I know will
be unique.

The .filter() could be used for update

e.g.:
Mymodel.objects.filter(1).update(key=value)

This is also bringing consistency in the code, but I agree this could be misleading.
The .get() is the main purpose.

Something to keep in mind as well is whether or not we want to allow
this to be coupled with extra args and kwargs.

Currently only kwargs are supposed to be used with get/filter. The only args that can be used currently are Q() objects (and couples but I think it's an issue).
This proposed design suggestion is to also allow scalar values (strings, int, etc) too.

charettes

unread,
Oct 31, 2018, 3:04:33 PM10/31/18
to Django developers (Contributions to Django itself)
My main concern with allowing extra args and kwargs to be mixed with the proposed
pk arg notation is that it would allow lookups such as

get(Q(is_active=True), pk)

Simon

Ian Foote

unread,
Oct 31, 2018, 7:00:28 PM10/31/18
to django-d...@googlegroups.com
I'm not in favour of this, it's too implicit for my liking and I don't think any gains outweigh the increased complexity of implementation.

Ian

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/a29eed0a-687a-4964-aec3-a25eeeb6f441%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Adam Johnson

unread,
Nov 1, 2018, 4:47:43 AM11/1/18
to django-d...@googlegroups.com
Count me as -1 too, it doesn't seem worth it to me to save the 3 characters 'pk='. It would increase complexity of implementation and complexity of comprehension ("two ways to do it").


For more options, visit https://groups.google.com/d/optout.


--
Adam

Ivan Anishchuk

unread,
Nov 1, 2018, 12:41:53 PM11/1/18
to django-d...@googlegroups.com
Not closely related, but what about composite keys? I think having such an implicit arg interpretation would make it much more complicated to use, say, a combination of charfield and integerfield as your key (primary or foreign doesn't matter): what does .get(('string', 123)) mean? .get(string=123) or .get(field1='string', field2=123)?

Actually, I think passing pairs isn't such a good idea either, but I can see some benefits over using dicts or unpacked args. (Assuming Q objects are not desired, for whatever reason.)

I'd prefer being sure which fields correspond to which values and about their order in the resulting query over saving three bytes on average (id= or pk=).

On the other hand, perhaps using a custom manager class would work in your case, consider adding a separate method 

Ivan Anishchuk

unread,
Nov 1, 2018, 12:53:36 PM11/1/18
to django-d...@googlegroups.com
(Sorry, accidental send.)

Consider adding a custom __call__ method to your manager class that would only accept values for pk lookup, nothing else. That way you can save four additional characters (qs(123) vs qs.get(id=123)) and that would be something I'm not against seeing in django, provided it's convenient enough and simple enough (not allowing arbitrary stuff that should be passed to filter() is the key, I think).

It would require further discussion to decide how different such a method should be from .get() - I can think of a few improvements I could find useful in shell but some of them might not for will in the current queryset api.

Ivan.

Josh Smeaton

unread,
Nov 5, 2018, 5:37:40 PM11/5/18
to Django developers (Contributions to Django itself)
I'm in the same boat as Simon - I've wanted this many times in the last few months, but only when working at the shell. I'd be +1 for get and -1 for filter also.

Tom Forbes

unread,
Nov 5, 2018, 8:47:31 PM11/5/18
to django-d...@googlegroups.com

I feel this would be a good addition to just .get(), I’ve wanted this while working with the shell. Model.objects.get(pk) feels very natural to me, and the common Model.objects.get(pk=pk) always felt overly verbose.

--

You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.

James Bennett

unread,
Nov 6, 2018, 2:48:36 AM11/6/18
to django-d...@googlegroups.com
I still don't understand the problem this is solving; is typing "pk=" (or "id=") that much of a burden? Or that frequently left out by accident?

As it stands, I agree with Adam that this adds implementation complexity (including potential future implementation complexity, as Ivan noted) and proliferates different ways to do the same thing, without presenting much in the way of concrete arguments for why it's needed. If there's a really convincing case to be made for this, I'm open to reading it when it's made, but for now I'd be -1 on the whole thing.

ludovic coues

unread,
Nov 6, 2018, 8:55:32 AM11/6/18
to django-d...@googlegroups.com
When experimenting with code in the shell, debugging or troubleshooting, I personally tend to do a lot of get. I know some object cause issue so I try to get them to poke them and see what's the problem.

When trying to get them, if I have the id, I always try to type Model.objects.get(id). Sometimes I correct myself before typing enter but that's something to remember and amount to a lot of little irritation, sometimes while trying to solve elusive issues or trying to fix asap some major issues in prod.


Maybe that feature belong in a third party app. Monkey-patching is a thing.

On Tue, Nov 6, 2018, 08:48 James Bennett <ubern...@gmail.com wrote:
I still don't understand the problem this is solving; is typing "pk=" (or "id=") that much of a burden? Or that frequently left out by accident?

As it stands, I agree with Adam that this adds implementation complexity (including potential future implementation complexity, as Ivan noted) and proliferates different ways to do the same thing, without presenting much in the way of concrete arguments for why it's needed. If there's a really convincing case to be made for this, I'm open to reading it when it's made, but for now I'd be -1 on the whole thing.

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.

Daniel Chimeno

unread,
Nov 6, 2018, 12:58:15 PM11/6/18
to Django developers (Contributions to Django itself)
This is something I've also experimented while working with a shell, I often mislead the .get(pk), with .get(pk=pk), 
but only at the shell, not in the views or other places (not sure why).
For that, I'm -1 to to include it in the core, and possible the best place is a third package app like django-extensions or similar.



C. Kirby

unread,
Nov 7, 2018, 3:33:09 PM11/7/18
to Django developers (Contributions to Django itself)
I bit the bullet and put together a small app to handle this, with maybe even less typing. It monkey patches all installed models so you can run Model.ident_(pk)

Chaim

Collin Anderson

unread,
Nov 7, 2018, 7:57:16 PM11/7/18
to django-d...@googlegroups.com
You could probably also just monkey patch like so:

from django.db.models import Manager, QuerySet
Manager.ident = QuerySet.ident = lambda self, pk: self.get(pk=pk)

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
Reply all
Reply to author
Forward
0 new messages