Opened 17 years ago

Last modified 13 years ago

#5535 closed

.get() should allow myforeignkey_id lookups — at Version 13

Reported by: David Cramer Owned by: nobody
Component: Database layer (models, ORM) Version: dev
Severity: Normal Keywords:
Cc: rkm, Simon Litchfield Triage Stage: Ready for checkin
Has patch: yes Needs documentation: yes
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Gary Wilson)

To allow easy accessibility as you can with .create on foreignkey_id calls, .get should allow the same.

e.g.

MyModel.objects.create(author_id=1) # Works
MyModel.objects.create(author=Author(id=1)) # Works
MyModel.objects.get(author_id=1) # Doesn't Work
MyModel.objects.get(author=Author(id=1)) # Works
MyModel.objects.get_or_create(author_id=1) # Doesn't Work

Change History (13)

comment:1 by James Bennett, 17 years ago

Triage Stage: UnreviewedDesign decision needed

This feels like it's trading consistency of lookup syntax (always use double-underscore) for gains in edge cases involving major performance constraints. I'm not sure that's the wisest course for Django to take.

comment:2 by James Bennett, 17 years ago

Resolution: worksforme
Status: newclosed

Also, on further reflection: your point here seems to be entirely about get_or_create, which takes the keyword argument defaults and will accept the "_id" syntax there, so you can already do this.

comment:3 by anonymous, 17 years ago

Resolution: worksforme
Status: closedreopened

This isn't just about get_or_create - you can't use fkeyname_id in .get() at all:

Model:

class A(models.Model):
    name = models.CharField(maxlength=30)
    fkey = models.ForeignKey('B', null=True)

Query:

>>> A.objects.get(fkey_id=1)
TypeError: Cannot resolve keyword 'fkey_id' into field. Choices are: id, name, fkey

in reply to:  2 comment:4 by David Cramer, 17 years ago

Replying to ubernostrum:

Also, on further reflection: your point here seems to be entirely about get_or_create, which takes the keyword argument defaults and will accept the "_id" syntax there, so you can already do this.

The problem is you can't use it outside of defaults. And that's where .get() itself comes into play.

comment:5 by anonymous, 17 years ago

Shouldn't that be fkey__id=1 (with two underscores)?

comment:6 by David Cramer, 17 years ago

You can use id on .get(), that's not the problem. The problem is you cannot use _id, as the actual field is myforeignkey_id by default, and works fine with .create()

comment:7 by James Bennett, 17 years ago

I still don't see why the lookup syntax needs to be made inconsistent just for sake of an implementation detail of foreign keys.

comment:8 by David Cramer, 17 years ago

It's exactly about consistency. You can use myfield_id on creation queries, why cant you use it on get queries?

comment:9 by James Bennett, 17 years ago

First off, the syntax we have right now is consistent. Any time you're working with a relation, you use a double underscore. It is true that there's an undocumented attribute on models which stores the raw value of a related object, and that this attribute has a single underscore in its name, but the Django ORM has never exposed the ability to perform lookups on arbitrary model attributes, even when those attributes spring from things in the database -- lookups are enabled for the names of the model's fields, and nothing else -- so it's hard to argue for any inconsistency existing in our not exposing lookups on one such attribute.

Second, I can't honestly see what the gain is here or what problem it would solve, other than saving a single character's worth of typing. The get_or_create() use case has already been shown not to apply because you can already do what you want with get_or_create().

So since it'd make the ORM lookup syntax inconsistent, and since no real-world problem has been advanced which would be solved by doing so, I'd be a strong -1.

comment:10 by James Bennett, 17 years ago

In the above, "stores the raw value of a related object" should be "stores the raw primary-key value of a related object". Silly typo.

comment:11 by David Cramer, 17 years ago

The benefit is you don't need an instance of the object to call it.

If you use .create() you need an instance, unless you pass it as !_id, if you use .get you don't need an instance.

If you use .get_or_create, you are forced to have an instance as .create requires it, and .get doesn't handle !_id.

A dirty hack is saying MyModel.objects.get_or_create(foreignkey=SomeModel(id=5)) but it's quite unneeded and could cause problems w/ the shared memory patch.

comment:12 by James Bennett, 17 years ago

If you're back to create and get_or_create, then again this is a "worksforme": you can use the _id syntax just fine there, and I don't know why you keep trying to bring that up. In create you can pass it directly, and in get_or_create you can pass it in defaults. And there's nowhere else you need an instance, because the __id syntax for lookups works just fine with the actual primary-key value.

So, again: where's the gain? What can't you do right now that you could do if we changed the lookup syntax?

comment:13 by Gary Wilson, 17 years ago

Description: modified (diff)

fixed description formatting.

Note: See TracTickets for help on using tickets.
Back to Top