Skip to content
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

Default value not working correctly. #265

Closed
conradogarciaberrotaran opened this issue May 8, 2019 · 12 comments
Closed

Default value not working correctly. #265

conradogarciaberrotaran opened this issue May 8, 2019 · 12 comments
Labels

Comments

@conradogarciaberrotaran
Copy link

Hi @miguelgrinberg.

I'm trying to add flask-migrate to an existing model with data. My first migration is adding a boolean column called enabled with default True.

class Prediction(db.Model):
    id = db.Column(db.String(32), primary_key=True)
    ...
    enabled = db.Column(db.Boolean, default=True)
    ...

The upgrade method of the migration is generated as following:

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.add_column('prediction', sa.Column('enabled', sa.Boolean(), nullable=False))
    # ### end Alembic commands ###

Applying this migration makes enabled with default as False.
Changing the migration to:
op.add_column('prediction', sa.Column('enabled', sa.Boolean(), nullable=False, default=True))
also makes enabled False by default.
Using server_default makes this error appear on flask db init:

sqlalchemy.exc.ArgumentError: Argument 'arg' is expected to be one of type '<class 'str'>' or '<class 'sqlalchemy.sql.elements.ClauseElement'>' or '<class 'sqlalchemy.sql.elements.TextClause'>', got '<class 'bool'>'

Am i doing something wrong? Thanks

@miguelgrinberg
Copy link
Owner

Can you share the code that you used with server_default and the complete error message including the stack trace?

The default argument is not going to work in a migration, because that is a SQLAlchemy level default, not a database default.

@conradogarciaberrotaran
Copy link
Author

Hi @miguelgrinberg, thanks for replying.
I tried server_default just with the value True passed to the column, .

    enabled = db.Column(db.Boolean, nullable=False, server_default=True)

Here's the stack trace:

Traceback (most recent call last):
  File "x/env/lib/python3.6/site-packages/flask/cli.py", line 529, in list_commands
    rv.update(info.load_app().cli.list_commands(ctx))
  File "x/env/lib/python3.6/site-packages/flask/cli.py", line 377, in load_app
    raise_if_not_found=False)
  File "x/env/lib/python3.6/site-packages/flask/cli.py", line 235, in locate_app
    __import__(module_name)
  File "x/app/__init__.py", line 4, in <module>
    from app.blueprints import ACTIVE
  File "x/app/blueprints/__init__.py", line 4, in <module>
    from app.blueprints.predictor import feed, syi, ensemble  # noqa
  File "x/app/blueprints/predictor/feed.py", line 5, in <module>
    from app.blueprints.predictor.utils import (
  File "/Users/cogarcia/dev/pyme-primeraventa-nomaquinable/app/blueprints/predictor/utils.py", line 7, in <module>
    from app.bin.unsubscribe_item import CONTROL_GROUP_PROBABILITY
  File "x/app/bin/unsubscribe_item.py", line 16, in <module>
    from app.models.models import Prediction
  File "x/app/models/models.py", line 5, in <module>
    class Prediction(db.Model):
  File "x/app/models/models.py", line 13, in Prediction
    enabled = db.Column(db.Boolean, nullable=False, server_default=True)
  File "x/env/lib/python3.6/site-packages/sqlalchemy/sql/schema.py", line 1266, in __init__
    args.append(DefaultClause(self.server_default))
  File "x/env/lib/python3.6/site-packages/sqlalchemy/sql/schema.py", line 2456, in __init__
    TextClause), 'arg')
  File "x/env/lib/python3.6/site-packages/sqlalchemy/util/langhelpers.py", line 1104, in assert_arg_type
    (name, ' or '.join("'%s'" % a for a in argtype), type(arg)))
sqlalchemy.exc.ArgumentError: Argument 'arg' is expected to be one of type '<class 'str'>' or '<class 'sqlalchemy.sql.elements.ClauseElement'>' or '<class 'sqlalchemy.sql.elements.TextClause'>', got '<class 'bool'>'

@miguelgrinberg
Copy link
Owner

The server_default should be given as text in the native format of the database, not as a Python type. See https://docs.sqlalchemy.org/en/13/core/metadata.html#sqlalchemy.schema.Column.params.server_default.

@conradogarciaberrotaran
Copy link
Author

Should i be using server_default though? I just want every row to have the value of the new column set to True.

@miguelgrinberg
Copy link
Owner

you have two options, either set the server default, or else create the column as nullable, then set it to your default using an UPDATE statement, and finally switch it to non-nullable.

@conradogarciaberrotaran
Copy link
Author

I have close to a hundred millions rows, i guess server_default will do.
Thanks so much for the help and your Flask contributions. Your blog got me into Flask.

If it's not too much to ask, how would you describe the server_default as True?

Thanks again

@miguelgrinberg
Copy link
Owner

Depends on the database that you are using. server_default='true' or server_default='1' are likely choices.

@conradogarciaberrotaran
Copy link
Author

Thanks, i'll try that. Im closing this issue.

@ppd0705
Copy link

ppd0705 commented Mar 23, 2021

thanks, that’s help me a lot

@ysomad
Copy link

ysomad commented Mar 23, 2021

thank you

@kulbirsaini
Copy link

IMO, correct way of doing this would be to use db.sql.True()_ instead of hardcoded value so that SqlAlchemy takes care of the cross database functionality.

enabled = db.Column(db.Boolean, server_default=db.sql.True_())

@zsoltbalint
Copy link

Based on the comments added to the False_ and True_ classes, the value should be accessed as a constant via the db.sql.false or db.sql.true function.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants