Opened 7 years ago

Closed 7 years ago

Last modified 18 months ago

#8070 closed Uncategorized (fixed)

related objects passed to model init are not cached/accessible

Reported by: gwilson Owned by: gwilson
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 gwilson 7 years ago.
8070.2.patch (6.4 KB) - added by gwilson 7 years ago.
corrected a comment

Download all attachments as: .zip

Change History (7)

Changed 7 years ago by gwilson

Changed 7 years ago by gwilson

corrected a comment

comment:1 Changed 7 years ago by gwilson

  • Needs documentation unset
  • Needs tests unset
  • Owner changed from nobody to gwilson
  • Patch needs improvement unset
  • Status changed from new to assigned
  • Triage Stage changed from Unreviewed to Ready for checkin

Someone else care to review?

comment:2 Changed 7 years ago by gwilson

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 7 years ago by gwilson

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

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

  • milestone 1.0 deleted

Milestone 1.0 deleted

comment:5 Changed 18 months ago by aaugustin

  • Easy pickings unset
  • Severity set to Normal
  • Type set to 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