Opened 3 years ago

Closed 3 years ago

Last modified 3 years ago

#27065 closed Bug (invalid)

Deferred fields not passed to inherited models' __class__.__dict__

Reported by: Jarek Glowacki Owned by: nobody
Component: Database layer (models, ORM) Version: 1.10
Severity: Normal Keywords: defer only inherited DeferredAttribute
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Possibly a regression, possibly me misunderstanding how this should now work in 1.10.

class A(models.Model):
    name = models.CharField(max_length=20)
    addy = models.CharField(max_length=200)


class B(A):
    name2 = models.CharField(max_length=20)

Calling:

b = B.objects.only('name').first()

we expect name2 and addy to get deferred. Calling b.get_deferred_fields(), we get both these field names returned as expected.

However, inspecting b.__class__.__dict__, we see that only the DeferredAttribute for name2 is available. To get the one for addy, we need to consult b's parent. This was not the case in 1.9.

See my PR to django-model-utils for context.

Change History (2)

comment:1 Changed 3 years ago by Tim Graham

I'd guess 7f51876f99851fdc3fef63aecdfbcffa199c26b9 is the commit in question. Can you come up with a test case that demonstrates a bug in normal Django usage? If not, that change sounds like an implementation detail. We might mention it in the release notes if you feel it might affect other projects.

comment:2 Changed 3 years ago by Jarek Glowacki

Keywords: only DeferredAttribute added
Resolution: invalid
Status: newclosed

Thanks, I've verified it's definitely commit 7f51876f99851fdc3fef63aecdfbcffa199c26b9 that causes this change in behaviour.

DeferredAttribute instances inherited from parent models can no longer be obtained through instance.__class__.__dict__ because the class is no longer dynamically created, but rather has the DeferredAttribute instances stapled on with setattr.

However, thanks to this change, a handle to the DeferredAttribute can be obtained by accessing the field directly from the instance's class, which looks considerably nicer and does pull through inherited fields.

So
deffered_field = instance.__class__.__dict__.get(field_name) # pre dj110
becomes
deferred_field = getattr(instance.__class__, field_name) # dj110+

I guess it can't hurt mentioning this in the release notes, though at the same time I don't see particularly many projects that would need to handle the DeferredAttributes directly. You're in a better position to make that call. At the very least this ticket can serve as an answer to people who google this problem.

Closing.

Version 0, edited 3 years ago by Jarek Glowacki (next)
Note: See TracTickets for help on using tickets.
Back to Top