0

I have a set of SelectField with Flask-WTF and I convert the default language with Flask-Babel.

Here is the snippet of my code:

from flask_babel import _, lazy_gettext as _l

class PaymentStatus(enum.Enum):
    PENDING = _l('PENDING')
    COMPLETED = _l('COMPLETED')
    EXPIRED = _l('EXPIRED')

    def __str__(self):
        return '{}'.format(self.value)

payment_status = [(str(_l(y)), y) for y in (PaymentStatus)]

class PaymentForm(FlaskForm):
    status_of_payment = SelectField(_l('Payment Status'), choices=payment_status)
    # ...
    # ...

And here is my model look like:

class Payment(db.Model):
    __tablename__ = 'payment'
    id = db.Column(db.Integer, primary_key=True)
    status_of_payment = db.Column(db.Enum(PaymentStatus, name='status_of_payment'))
    # ...
    # ...

And when I try to insert the value from the Flask-WTF form to my database, I got some error.

Here is the snippet how I insert it to database:

if form.validate_on_submit():
    payment = Payment(
        # payment_status=form.status_of_payment.data
        payment_status=PaymentStatus.PENDING.value
        # ...
        # ...
    )

The value of the enum PENDING also converted to the language on preferred language on my browser, so I got this error message:

sqlalchemy.exc.StatementError: (builtins.LookupError) "MENGUNGGU" is not among the defined enum values

for more information: "MENGUNGGU" = is Indonesian language for "PENDING" in English.

So the problem here is, when I insert the SelectField value, it also converts the language to my preferred browser language, and my database which is PostgreSQL block it, because I don't define the value on my enum type.

So, the point of my question is, can we excluded the i18n & l10n value from Flask-Babel when we want to insert the value to a database..?, or what should I do to face this..?

desertnaut
  • 57,590
  • 26
  • 140
  • 166
Tri
  • 2,722
  • 5
  • 36
  • 65
  • My opinion is that you should not use the translate value on the enum. It doesn't make sense to me have a internacionalizated enum, handle internacionalization in the form tier – geckos Oct 02 '19 at 15:08
  • 1
    Another shorter option would seek for a mapping from intercionalizated value to deafault language on enum class it would have something to achieve this – geckos Oct 02 '19 at 15:11
  • Have a look at my edited answer. – stasiekz Oct 03 '19 at 14:07
  • No, your first answer also works in my case, I'll accept the answer later while now I still experimenting on the code. – Tri Oct 03 '19 at 14:28

1 Answers1

2

You should swap values in your choices because the first element in the tuple is the actual value that will be submitted and the second one is the presentation:

payment_status = [(y.name, _l(str(y.value))) for y in PaymentStatus]

Thanks to this you'll have translated names and proper values submitted.

Enum's name should be stored in your database instead of the value.

stasiekz
  • 1,775
  • 5
  • 22
  • I think the first answer before edited is more efficient, because we don't need to declare the `_l()` in each value of the enum variable. Just looping it like your first answer. – Tri Oct 03 '19 at 14:30
  • The correct answer is like this: `payment_status = [(y.name, _l(str(y.value))) for y in (PaymentStatus)]` swap the `_l()` position with `str()` position. – Tri Oct 04 '19 at 06:32