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
Handle DRF MoneyField validation in to_internal_value #650
Handle DRF MoneyField validation in to_internal_value #650
Conversation
24dda35
to
66cd4c9
Compare
Codecov Report
@@ Coverage Diff @@
## main #650 +/- ##
==========================================
+ Coverage 97.95% 97.96% +0.01%
==========================================
Files 29 29
Lines 976 985 +9
Branches 192 193 +1
==========================================
+ Hits 956 965 +9
Misses 13 13
Partials 7 7
Continue to review full report at Codecov.
|
from moneyed.classes import CurrencyDoesNotExist | ||
|
||
|
||
PrimitiveMoney = namedtuple("PrimitiveMoney", ["amount", "currency"]) |
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.
What is the primary purpose of this class and why Money
won't work instead?
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.
Oh, I think that it is here to avoid validation inside Money
, right? so it is deferred to to_internal_value
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.
Exactly, creation of a Money instance and validation of its data will now only happen in to_internal_value. PrimitiveMoney will only "transport" the data to to_internal_value without doing any validation
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.
Cool! I'd suggest replacing namedtuple
with a handwritten class with __slots__
(as it is a bit faster and potentially harder to misuse) and renaming it to _PrimitiveMoney
to denote, its private use. What do you think?
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.
Also, a short comment describing the purpose of this class would be helpful
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.
Cool! I'd suggest replacing
namedtuple
with a handwritten class with__slots__
(as it is a bit faster and potentially harder to misuse)
The only (small) drawback I see with only __slots__
is immutability, which I kind of like in cases like this. Though I won't say I have a very strong opinion about it here. It seems like it's possible to combine namedtuple
and __slots__
to get an immutable object. What do you think, should we do that?
renaming it to
_PrimitiveMoney
to denote, its private use
Sounds good!
Also, a short comment describing the purpose of this class would be helpful
Definitely, I'll add in a comment
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.
@Stranger6667 I bumped to use the namedtuple
+ __slots__
combination just to get a feel of what that would look like. Let me know if you want me to change it.
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.
Maybe something like this to avoid using namedtuple
at all?
class _PrimitiveMoney:
__slots__ = ("amount", "currency")
def __init__(self, amount, currency):
self.amount = amount
self.currency = currency
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.
Alright, I bumped to your suggestion.
ded2183
to
54a27c1
Compare
Fixes #601
Fixes #637
Move any form of
Money
validation toMoneyField.to_internal_value
. A quick peek at serializers' validation implementation shows that errors bubbling up from.to_internal_value
will be handled.Although, since the DRF
MoneyField
is a composite field per default, I'm slightly uncertain of how to react when finding an invalid currency value. At the moment, this will mark up aninvalid_currency
error for the declaredMoneyField
, which might feel a little off, especially when working with explicitly declared amount and currency fields (e.g.money_currency
declared as aChoiceField
), since that'll then always result in 2 field errors.Since
MoneyField.get_value
is declared the way it is, even if there's no%_currency
-field or default currency declared for a serializer, any data passed matching that key will be silently/implicitly captured.. Consider the following test case that currently fails: