Opened 20 years ago
Closed 17 years ago
#1667 closed defect (fixed)
OneToOne and ForeignKey related objects are cached differently
| Reported by: | Owned by: | nobody | |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | dev |
| Severity: | normal | Keywords: | 121-rewrite |
| Cc: | Triage Stage: | Design decision needed | |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Looks like ForeignKeys respect model's custom default manager and OneToOneField don't. Here's an example.
There are 3 models: Author, Article and Contact. Article refers to Author with ForeignKey and Contact refers to Author with OneToOneField. Author has a custom default manager that gives out only authors with their 'available' field set to True:
class AvailableAuthorManager(models.Manager):
def get_query_set(self):
return super(AvailableAuthorManager, self).get_query_set().filter(available__exact=True)
class Author(models.Model):
name = models.CharField(maxlength=50)
available = models.BooleanField(default=True)
objects = AvailableAuthorManager()
class Article(models.Model):
author = models.ForeignKey(Author)
title = models.CharField(maxlength=50)
class Contact(models.Model):
author = models.OneToOneField(Author)
address = models.CharField(maxlength=50)
Then if you have an author with available=False and an article and a contact reefering to it you get:
- article.author -- raises an exception DoesNotExist
- contact.author -- returns the author
Looks like this should behave the same way in both cases. However I'm not sure how exactly but I tend to think that it should raise an exception because managers are supposed to be the ultimate mechanism to access model objects.
Change History (11)
comment:1 by , 20 years ago
comment:2 by , 20 years ago
| Summary: | OneToOne and ForeignKey treat managers differently → OneToOne and ForeignKey related objects are cached differently |
|---|
I tested it further and it seems you're right. The behavior that I was observing was caused by caching objects:
author = Author(name='...') author.save() article = Article(author=author, title='...') article.save() contact = Contact(author=author, address='...') contact.save() article.author # OK contact.author # OK author.available=False author.save() article.author # Exception contact.author # OK
So it seems that accessing object through OneToOne does use cached object and ForeignKey does a query. I'm changing summary appropriately. Now I think cached version should be used in both cases because caches are usually expected to be out of sync with reality.
comment:3 by , 20 years ago
Here's more. If you get a contact or an article with select_related() you will always have their authors. I mean selected_related() seems to not use managers at all.
I sorts understand why is this happening but I'm not very familiar with this code. May be I should file another bug for this?
comment:4 by , 19 years ago
| Type: | defect |
|---|
comment:5 by , 19 years ago
| Type: | → defect |
|---|
comment:6 by , 19 years ago
| Cc: | added; removed |
|---|---|
| Keywords: | rthml tab space editor js added |
| Summary: | OneToOne and ForeignKey related objects are cached differently → hi-world cup |
comment:7 by , 19 years ago
| Summary: | hi-world cup → OneToOne and ForeignKey related objects are cached differently |
|---|
comment:8 by , 19 years ago
| Cc: | removed |
|---|---|
| Keywords: | rthml tab space editor js removed |
| Triage Stage: | Unreviewed → Design decision needed |
comment:9 by , 18 years ago
| Version: | magic-removal → SVN |
|---|
comment:10 by , 18 years ago
| Keywords: | 121-rewrite added |
|---|
comment:11 by , 17 years ago
| Resolution: | → fixed |
|---|---|
| Status: | new → closed |
This is actually long fixed. ForeignKey's and OneToOne behave now consistently (though they do omit default manager on purpose).
Using the models and manager outlined here, I created one Author, and an Article and a Contact related to it. Then I set the Author's 'available' field to False and got a DoesNotExist exception for both 'article.author' and 'contact.author'. Maybe we're on different revisions and something changed between them?