Opened 8 years ago

Closed 8 years ago

Last modified 3 years ago

#8070 closed Uncategorized (fixed)

related objects passed to model init are not cached/accessible

Reported by: Gary Wilson Owned by: Gary Wilson
Component: Core (Other) Version: master
Severity: Normal Keywords:
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

Models:

from django.db import models

class Color(models.Model):
    name = models.CharField(max_length=10)

class Knight(models.Model):
    favorite = models.ForeignKey(Color)

Neither saved or unsaved related objects get cached:

# Unsaved object.
>>> k = Knight(favorite=Color())
>>> hasattr(k, '_favorite_cache')
False

# Saved object.
>>> k = Knight(favorite=Color.objects.create(name='blue'))
>>> hasattr(k, '_favorite_cache')
False

# But assignment with saved or unsaved objects does cache correctly.
>>> k = Knight()
>>> k.favorite = Color()
>>> hasattr(k, '_favorite_cache')
True
>>> k = Knight()
>>> k.favorite = Color.objects.create(name='blue')
>>> hasattr(k, '_favorite_cache')
True

Also, in the saved related object case above, we do an extra query to refetch the object by id.

There's also a problem when trying to access the field when it was passed an unsaved object in the init:

# Unsaved object.
>>> k = Knight(favorite=Color())
>>> k.favorite
Traceback (most recent call last):
...
DoesNotExist

# Saved object.
>>> k = Knight(favorite=Color.objects.create(name='blue'))
>>> k.favorite
<Color: blue>

The attached patch does both:

  • Caches saved or unsaved related object passed to the Model init.
  • Allows unsaved related objects to be accessed when they were passed to the Model init.

Attachments (2)

8070.patch (5.4 KB) - added by Gary Wilson 8 years ago.
8070.2.patch (6.4 KB) - added by Gary Wilson 8 years ago.
corrected a comment

Download all attachments as: .zip

Change History (7)

Changed 8 years ago by Gary Wilson

Attachment: 8070.patch added

Changed 8 years ago by Gary Wilson

Attachment: 8070.2.patch added

corrected a comment

comment:1 Changed 8 years ago by Gary Wilson

Owner: changed from nobody to Gary Wilson
Status: newassigned
Triage Stage: UnreviewedReady for checkin

Someone else care to review?

comment:2 Changed 8 years ago by Gary Wilson

Patch note: #6886 made the type checking happen on assignment, so we don't need to do the checking in the init anymore as long as you are setting using the attribute named by field.name.

comment:3 Changed 8 years ago by Gary Wilson

Resolution: fixed
Status: assignedclosed

(In [8185]) Fixed #8070 -- Cache related objects passed to Model init as keyword arguments. Also:

  • Model init no longer performs a database query to refetch the related objects it is passed.
  • Model init now caches unsaved related objects correctly, too. (Previously, accessing the field would raise DoesNotExist error for null=False fields.)
  • Added tests for assigning None to null=True ForeignKey fields (refs #6886).

comment:4 Changed 5 years ago by Jacob

milestone: 1.0

Milestone 1.0 deleted

comment:5 Changed 3 years ago by Aymeric Augustin

Easy pickings: unset
Severity: Normal
Type: Uncategorized
UI/UX: unset

Allows unsaved related objects to be accessed when they were passed to the Model init.

Django accepted this but the relation wasn't saved, see #10811. I'm going to remove the test for that bug-prone behavior.

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