Opened 16 years ago

Closed 13 years ago

Last modified 12 years ago

#9029 closed (fixed)

`get_or_create` broken due to inconsistent behaviour between `create` and `filter` on Manager, RelatedManager, QuerySet, etc.

Reported by: Tai Lee Owned by: aaron
Component: Database layer (models, ORM) Version: dev
Severity: Keywords: get_or_create get create filter FieldError
Cc: Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

When calling create, the value for a ForeignKey field must be an instance of the appropriate model, e.g. Model.objects.create(relatedfield=obj). To use a primary key as the value instead of a model instance, you must use the database field name as the keyword, e.g. Model.objects.create(relatedfield_id=N).

When calling filter (or get), you cannot use the database field name as the keyword, but you can use either a model instance or a primary key as the value, e.g. Model.objects.filter(relatedfield_id=N does not work, but Model.objects.filter(relatedfield=obj) and Model.objects.filter(relatedfield=N) both work.

This makes it impossible to use primary keys as values for ForeignKey fields with get_or_create, e.g. Model.objects.get_or_create(relatedfield_id=N, defaults={'otherfield': otherfield}) raises a FieldError exception.

Attachments (3)

9029-get_or_create-r9014.diff (525 bytes ) - added by Tai Lee 16 years ago.
failing test case
9029-get-or-create-r12805.diff (1.7 KB ) - added by aaron 14 years ago.
Patch with slightly altered test, but no documentation
9029-get-or-create-r14733.diff (2.4 KB ) - added by Tai Lee 13 years ago.
Updated tests to apply cleanly against r14733.

Download all attachments as: .zip

Change History (13)

by Tai Lee, 16 years ago

failing test case

comment:1 by Tai Lee, 16 years ago

Has patch: unset

Patch has failing test case, but not a fix.

in reply to:  description comment:2 by Julian Bez, 16 years ago

Replying to mrmachine:

e.g. Model.objects.filter(relatedfield_id=N does not work, but Model.objects.filter(relatedfield=obj) and Model.objects.filter(relatedfield=N) both work.

How about Model.objects.filter(relatedfield__id=N)? That usually works. But yes, it does not work with get_or_create and creating new objects, because everything with __ gets stripped for the create query.

comment:3 by Jacob, 15 years ago

Triage Stage: UnreviewedAccepted

Julian's right that Model.objects.get_or_create(related__id=N, defaults={'related': related_instance}) works and is an acceptable-if-ugly workaround.

However, there's no reason not to make the test given in the patch work, so I'm marking this accepted. If someone wants to work on it, the place to look is in the QuerySet implementation.

by aaron, 14 years ago

Patch with slightly altered test, but no documentation

comment:4 by aaron, 14 years ago

Has patch: set
Needs documentation: set

comment:5 by aaron, 14 years ago

Needs documentation: unset

Oops, not actually sure if this needs docs.

comment:6 by aaron, 14 years ago

Owner: changed from nobody to aaron
Status: newassigned

by Tai Lee, 13 years ago

Updated tests to apply cleanly against r14733.

comment:7 by Tai Lee, 13 years ago

milestone: 1.3
Triage Stage: AcceptedReady for checkin

Patch looks good to me. Tests updated to apply against r14733, and pass locally on sqlite, postgresql and mysql.

comment:8 by Andrew Godwin, 13 years ago

Resolution: fixed
Status: assignedclosed

(In [15156]) Fixed #9029 -- Allow use of fieldname_id with get_or_create. Thanks to aaron and mrmachine.

comment:9 by Andrew Godwin, 13 years ago

(In [15157]) [1.2.X] Fixed #9029 -- Allow use of fieldname_id with get_or_create. Thanks to aaron and mrmachine.

Backport of [15156] from trunk

comment:10 by Jacob, 12 years ago

milestone: 1.3

Milestone 1.3 deleted

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