Opened 7 years ago

Closed 4 years ago

Last modified 4 years ago

#9029 closed (fixed)

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

Reported by: mrmachine Owned by: aaron
Component: Database layer (models, ORM) Version: master
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: UI/UX:

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 mrmachine 7 years ago.
failing test case
9029-get-or-create-r12805.diff (1.7 KB) - added by aaron 5 years ago.
Patch with slightly altered test, but no documentation
9029-get-or-create-r14733.diff (2.4 KB) - added by mrmachine 5 years ago.
Updated tests to apply cleanly against r14733.

Download all attachments as: .zip

Change History (13)

Changed 7 years ago by mrmachine

failing test case

comment:1 Changed 7 years ago by mrmachine

  • Has patch unset
  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

Patch has failing test case, but not a fix.

comment:2 in reply to: ↑ description Changed 7 years ago by julianb

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 Changed 6 years ago by jacob

  • Triage Stage changed from Unreviewed to Accepted

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.

Changed 5 years ago by aaron

Patch with slightly altered test, but no documentation

comment:4 Changed 5 years ago by aaron

  • Has patch set
  • Needs documentation set

comment:5 Changed 5 years ago by aaron

  • Needs documentation unset

Oops, not actually sure if this needs docs.

comment:6 Changed 5 years ago by aaron

  • Owner changed from nobody to aaron
  • Status changed from new to assigned

Changed 5 years ago by mrmachine

Updated tests to apply cleanly against r14733.

comment:7 Changed 5 years ago by mrmachine

  • milestone set to 1.3
  • Triage Stage changed from Accepted to Ready for checkin

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

comment:8 Changed 4 years ago by andrewgodwin

  • Resolution set to fixed
  • Status changed from assigned to closed

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

comment:9 Changed 4 years ago by andrewgodwin

(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 Changed 4 years ago by jacob

  • milestone 1.3 deleted

Milestone 1.3 deleted

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