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 #30902 -- Added __str__() for model choice enums. #11964
Conversation
I thought there was a reason that we chose not to do this, but I'm struggling to remember the reasoning now. I must say, however, this wouldn't be the only case I've come across where values attached to an object that has been saved are not equivalent to the value that is populated from the rows returned from the database. I have no objection if it generally works without breaking anything else - we're already being rather strict with how these enums are defined and used to ensure that things play nicely. |
Yeah, that's where I am right now. 😀 |
…peration tests.
Refs django#11964. Thanks Scott Stevens for testing this upcoming feature and the report.
…b_features. This will notably silence the warnings issued when running the test suite on MySQL.
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.
Do we have a test as well to ensure the IntegerChoices
also doesn't return a enum value but an integer? Not sure how achievable it would be.
By defining This makes me wonder if this |
Didn't know about this method's existence 👍 |
Hmm... This is where I get a little dubious about this. If we define |
Two comments: First of all, we do not need to take care of any type other than @NyanKiyoshi said:
but this is a false dichotomy; an instance of Secondly, the conversion of a x if isinstance(x, str) else str(x) where we currently do the intuitive All in all, I think the current behavior is the least of possible evils, and the issue should be solved by documentation, not behavior change. [1] The names "Choices", "TextChoices" etc. came later; the comment refers to it as "ChoiceStrEnum". |
On second thought, having looked at the ticket again, it may make sense to introduce a behavior change, but in |
Thanks @shaib for your input. (See bottom) I haven't had the time yet to think through your last suggestion, but I wanted to comment with what I've got thus far, since I don't think we can settle with the current situation (that I know you since re-commented):
OK so...
But, every other usage is not expected:
OK, we can work around that. Ultimately we can say, "but they're Enums, and
This is the "the issue should be solved by documentation, not behavior change" alternative. But that's not how people use model values. That they're Enums is an We can't saddle that on our users, who are doing this:
Recall though that,
Or really this:
That's (techical term :) broken. So from the super helpful #11223 (comment)
At this point, I'd say Yes to that. IIRC the objections on the mailing list to having Enums (at all) were that their behaviour wasn't helpful enough, so, in order to get past that, we opted to adjust that behavioiur. This, then, is just more in that vein. We subclass Enum to make it suitable for use as a Django model attribute choice. That its str behaviour is different from the base class is OK, on that line. (We can call-out that difference in the docs.) However...
Not sure yet what this entails, so could be a possibility. (Can't predict instantly what it would look like, or what other issues it would throw up...) Thoughts? |
Thanks for your analysis @carltongibson. So we tried to keep things as close to the standard enum as possible, but - as I mentioned earlier - we have had to make some choices to ensure things behave as expected, e.g. enforcing unique members, adding display labels. This is also why I steered away from naming such as So looking back at the options in #11223 (comment) which can be summarised as the following:
I'd also add these additional options for consideration:
Option 1 is not viable as we need to have concrete types defined - it solves so many other issues related to comparison, etc. Option 2 doesn't make sense to me - it would conflict with the problem that we have at the moment anyway. Options 3 and 5 would leave a discrepancy between I'm not keen on option 6 - that sounds like transparently calling In light of this, I think that we're stuck with option 4 - to change I think we just need to now accept the fact that we are not providing support for generic enums - we are providing a |
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.
After thinking through all the options I feel this is the only suitable solution. Thanks @carltongibson!
Yes, @carltongibson @pope1ni I'm convinced. Thanks! |
OK, thank you both. Do we need to call something out in the docs? (I shall look... — but any input welcome. 😀) |
I don't think anything is needed in the docs, but I'd put a short
summary of why we define `__str__()` this way in comments in the code.
|
There is a bulleted list of differences to standard enums in the documentation that you could add something to, but then again we don't mention the special handling of |
OK, thanks again both. I'm just doing something else, then I'll come back and adjust this. |
Allows expected behavior when cast to str, also matching behaviour of created instances with those fetched from the DB. Thanks to Simon Charette, Nick Pope, and Shai Berger for reviews.
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.
Thanks y'all for a great discussion 🚀
This prevent having to pass simple_col through multiple function calls by defining whether or not references should be resolved with aliases at the Query level.
This prevent having to pass simple_col through multiple function calls by defining whether or not references should be resolved with aliases at the Query level.
This prevent having to pass simple_col through multiple function calls by defining whether or not references should be resolved with aliases at the Query level.
This prevent having to pass simple_col through multiple function calls by defining whether or not references should be resolved with aliases at the Query level.
…econstruct(). Fixed for new operations in 952f05a.
Allows expected comparison against strings, matching behaviour of created
instances with those fetched from the DB.
@shaib @pope1ni — This looks right to me, especially given the example on the ticket of the difference between created and retrieved instances but, what do you think? Thanks!