-
-
Notifications
You must be signed in to change notification settings - Fork 31.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixed #10506, #13793, #14891, #20932, #25201, #25897 -- Refactored managers inheritance #6175
Conversation
3c2f20a
to
c1bc1d5
Compare
elif getattr(related_model._default_manager, 'use_for_related_fields', False): | ||
warnings.warn( | ||
"use_for_related_fields is deprecated use Meta.related_manager_name" | ||
"instead. Not that Meta.related_model_name applies to all relations" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that ...
c1bc1d5
to
efa14c1
Compare
elif getattr(related_model._default_manager, 'use_for_related_fields', False): | ||
warnings.warn( | ||
"use_for_related_fields is deprecated use Meta.related_manager_name" | ||
"instead. Note that Meta.related_model_name applies to all relations" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
related_manager_name
not related_model_name
This looks really nice IMO! Much easier to understand than the previous system. The main thing I notice is that we still have a discrepancy between different types of relations in terms of which manager is the fallback default. The relation types that support(ed) I'm not sure how we could make that change in a backwards-compatible way, though :/ |
Yes that discrepancy is very annoying. I'd have to think about it some more but changing either one of them has significant consequences. Upgrading But if we wanna do it, it should be pretty easy to do using the deprecation path I added to the other PR. If the related model has |
@cached_property | ||
def base_manager(self): | ||
if self.base_manager_name: | ||
return self.managers_map[self.base_manager_name] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to self, this should raise a helpful message in case of KeyError
. Same for default_manager
and related_manager
below.
Maybe it really is better for to-one relations to default to So I think that we should either a) go through a deprecation as you outlined to make all of the relation types default to I'm still thinking through which of those options I prefer. I think I'm actually leaning towards |
(In any case, regardless of which of the above options we pick, it deserves much clearer -- and more accurate -- documentation than |
I think it's worth thinking about Now that we have I'm not too sure about b) I don't think in most cases you really need to differentiate between "to-one" and "to-many" relations as far as custom managers go. I think my preferred option would have been for everything to use |
Or maybe just deprecate |
I'm ok with having |
I just did a little experiment #6179, which demonstrates that So effectively Now, if we ever wanted to add such feature and want the fallback to be consistent or even just change the to-one managers without adding I see the following usage of
Other than the last two bullets, all usages are exactly where we'd expect. Having it for to-one relations is I guess debatable but personally it doesn't strike me as the obvious choice. If you are OK with missing records on a "to-many", why not on "to-one"? Unless it could break Django's internal somehow, although I can't see how (famous last words)... I see the following options:
I think my vote goes to 2 and 3, but I can live with 1. The |
For completeness, I made another experiment #6182 that implements all the proposed |
@timgraham what's the timeline like for 1.10 alpha? One option could be to go ahead with the refactor, deprecate Then approach the orthogonal
|
1.10 alpha is scheduled for May 16: https://code.djangoproject.com/wiki/Version1.10Roadmap |
@loic Sorry it took me a while to get back to this. As I tried to say above, I do think there is a somewhat-reasonable rationale behind the use of The situation with a to-many relationship is quite different, because you are getting back a queryset of objects, and having that queryset filtered by your default manager doesn't fundamentally change the contract in any way. Plus, you actually have access to both the manager and queryset (and their methods) when you use the to-many relation, therefore it's much more likely that it is useful to you to have your custom manager available (whereas in a to-one relation, the use of a custom manager is completely irrelevant to you, unless it's a filtering manager). I'm not sure at this moment what that implies we should do. It may be that we should still aim for stronger consistency and ignore these differences. But I think we need to be clear that there are good practical reasons for the current apparent inconsistency, before we propose to change it. (I like your latest idea of splitting the two changes up; always good to split a big change into smaller independent changes when we can.) |
Thanks Carl.
That's very true. So the more I think of it, the less I believe we should go for a blanket |
👍 on punting the tricky API issue and merging your excellent refactoring work :-) |
efa14c1
to
48232d3
Compare
48232d3
to
d5a6a32
Compare
35fff41
to
67afb09
Compare
f41bf68
to
1dec244
Compare
The proposed changes make sense to me. |
I added some keywords to Trac tickets to help identify issues that this PR might affect. |
aeb8902
to
f4bf0a1
Compare
Thanks Tim, I squashed the tentative commit and updated the docs with the new behavior. Barring any objections I think this is good to go. |
@@ -409,6 +409,12 @@ Models | |||
|
|||
* ``Model.__init__()`` now sets values of virtual fields from its keyword | |||
arguments. | |||
* The new :attr:`Meta.base_manager_name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing blank line above due to rebase
You may also squash my docs commit into the appropriate commit(s). |
659bec7
to
7b396ad
Compare
Needs a rebase, otherwise LGTM. |
Does this fix #14891 as the commit message indicates? It seems like more work needs to be done to add |
I think anything related to In the space of relation managers customization, I think the |
Since I mention the future |
I should probably also mention that we thought of calling the In favor of keeping the suffix though, I think (it's been a long while!) we also considered that we may want to futurely support something like |
0210c75
to
93a7ec5
Compare
93a7ec5
to
a2e4e1c
Compare
I think we could drop the _name suffix of the options without creating any confusion. |
2863bb5
to
f82edfa
Compare
…new APIs to specify models' default and base managers. This deprecates use_for_related_fields. Old API: class CustomManager(models.Model): use_for_related_fields = True class Model(models.Model): custom_manager = CustomManager() New API: class Model(models.Model): custom_manager = CustomManager() class Meta: base_manager_name = 'custom_manager' Refs #20932, #25897. Thanks Carl Meyer for the guidance throughout this work. Thanks Tim Graham for writing the docs.
I'm aborting the removal of the Since the other types of API could at least in theory support both a manager name and a manager class/instance (e.g. model.m2m(manager=MyManager()), or ForeignKey(manager=MyManager(), related_manager=MyReveseManager()) whereas |
f82edfa
to
ed0ff91
Compare
Refactor managers inheritance and introduce new APIs for specifying the default and base manager of a given model. Also deprecate
use_for_related_fields
._base_manager
and_default_manager
properties.use_for_related_fields
, and legacy manager inheritance)_base_manager
and_default_manager
, they've always existed but should be public APIs (so 3rd party apps use them).