I can't seem to find a way to update an entity in the database using sqlalchemy ORM
Here's what I'm doing:
query = Table(self.table_name, self.sql_controller.metadata, autoload=True).select(ItemEntity)
database_items: List[ItemEntity] = session.execute(query).all()
database_items[0].Sell_price = 50000
But that raises an exception "AttributeError: can't set attribute"
I see that the same manipulation is being done in the official documentation of sqlalchemy https://docs.sqlalchemy.org/en/14/tutorial/orm_data_manipulation.html#updating-orm-objects
Can someone point me in the right direction? It's really irritating to fail at basic CRUD operations.
Table objects are not part of SQLAlchemy ORM, they are part of SQLAlchemy Core. In order to use ORM you'll want to do something like this:
from sqlalchemy import create_engine
from sqlalchemy import select
from sqlalchemy.ext.automap import automap_base
from sqlalchemy.orm import Session
engine = create_engine("sqlite://", echo=True)
# create test environment
with engine.begin() as conn:
conn.exec_driver_sql("CREATE TABLE my_thing (id int primary key, sell_price int)")
conn.exec_driver_sql("INSERT INTO my_thing (id, sell_price) VALUES (1, 123)")
Base = automap_base()
class MyThing(Base):
__tablename__ = "my_thing"
Base.prepare(autoload_with=engine)
# test
with Session(engine) as sess:
thing_1 = sess.scalar(select(MyThing).where(MyThing.id == 1))
thing_1.sell_price = 456
sess.commit()
""" SQL emitted:
UPDATE my_thing SET sell_price=? WHERE my_thing.id = ?
[generated in 0.00032s] (456, 1)
"""
I'm trying to write pytest fixture app that create all tables before test and drop all of them after finishing it.
#pytest.fixture
def app(request):
"""Create and configure a new app instance for each test."""
app = create_app("test") # factory function that return Flask app
from academy.models import (User, Auth)
def finalizer():
db.session.remove()
db.drop_all()
print("tables after drop_all: ", db.engine.table_names()) # empty list
request.addfinalizer(finalizer)
db.create_all()
print("tables after create_all: ", db.engine.table_names()) # <<< Error here
return app
by this app fixture I got the following output:
tables after create_all: ['user', 'auth']
tables after drop_all: []
tables after create_all: []
tables after drop_all: []
tables after create_all: []
No problem will occur if I ran a single test, But with multiple tests only the first one will run as expected & the remaining will fail.
I wonder why flask-sqlalchemy can't create tables after dropping it !
I have a simple project here, with two models that contain an attribute called telefone in both.
telefone is phone in portuguese.
Code
class Medico (models.Model):
nome = models.CharField(max_length=50)
endereco = models.CharField(max_length=60)
cpf = models.CharField(unique=True, max_length=11)
telefone = models.CharField(max_length=15)
especialidade = models.ForeignKey(Especialidade, on_delete=models.CASCADE)
def __str__(self):
return self.nome
class Paciente (models.Model):
nome = models.CharField(max_length=50)
endereco = models.CharField(max_length=60)
cpf = models.CharField(unique=True, max_length=11)
telefone = models.CharField(max_length=15)
def __str__(self):
return self.nome
I did the makemigrations and migrate, everything worked as expected, I'm using MySQL as BD.
But for some reason, the phone field is int int in my BD for both the patient table and the medical table, see the image:
Now the other fields are correct, could anyone tell me why this is happening?
EDIT 01:
migrations.CreateModel(
name='Paciente',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('nome', models.CharField(max_length=50)),
('endereco', models.CharField(max_length=60)),
('cpf', models.CharField(max_length=11, unique=True)),
('telefone', models.CharField(max_length=15)),
],
),
continue
Delete all the files in yourapp/migrations, except __init__.py
Then run these 2 commands :
python manage.py makemigrations
python manage.py migrate
UPDATE :
If that does not work, delete all tables from MySQL database and let Django recreate them using python manage.py makemigrations and python manage.py migrate
I have a Django model with a JSONField to handle multilingual text as follows:
from django.contrib.postgres.fields import JSONField
def default_language_JSON():
content = {}
for lang in settings.LANGUAGES:
content[lang[0]] = ''
return content
class Entity(PolymorphicModel, ShowFieldType):
displayedNames = JSONField(
null = True,
blank = True,
verbose_name=_('Displayed names'),
help_text= _('These names are usually created automatically'),
default = default_language_JSON
)
...
When I try to dump the data with:
python3 manage.py dumpdata --natural-foreign --indent 4 --format=xml --verbosity 1 -o Database.xml
I get the error:
CommandError: Unable to serialize database: expected string or bytes-like object
I suppose it may have to do with the way the JSONField is serialized and I suspect the answer might be the encoder that should be used (as described in the documentation)
If I try dumping data in JSON or YAML no such error appears.
I use Django 2.1.4 in Ubuntu 16.04 with PostgreSQL 9.5
Any ideas?
A field has been added to one of my MySQL table previously:
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2017-09-14 00:49
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('my_app', '0102_previous_migrations'),
]
operations = [
migrations.AddField(
model_name='my_client',
name='my_team',
field=models.CharField(choices=[('Unassigned', 'Unassigned'), ('ACT', 'ACT'), ('Korea', 'Korea'), ('National', 'National')], default='Unassigned', max_length=255, verbose_name='My Team'),
),
]
So users have a choices of the above selection in my UI and will be saved into the table my_client:
Unassigned
ACT
Korea
National
The changes have been deployed and now a beginner like me would like to change, i.e. remove Korea and add 2 new choices: NSW and SA
How would I go about this? Do I need another migration or I will just need to change those choices in the models?
I use this in my model now like this:
class Client(MyAppModel):
TEAM_CHOICES = (
('Unassigned', 'Unassigned'),
('ACT', 'ACT'),
('Korea', 'Korea'),
('National', 'National'),
)
DEFAULT_TEAM = 'Unassigned'
my_team = models.CharField(verbose_name='MyTeam', null=False, max_length=255, choices=TEAM_CHOICES, default=DEFAULT_TEAM)
Update:
Base on the comment I have, I will need a migration too, a AlterField?
Do I also have to update all the existing value right now in the table my_client if any of them is having Korea to say Unassigned if I would like to remove Korea as a choice? What command can I use in the migration?
A high-level approach:
Create a migration which only adds the new choice. Write a method to take all models with the old choice, and give them a proper new choice migration.RunPython. Create a migration which removes the old choice.
Figure this out later, hope it helps others beginner like me.
I have to update the Client model
class Client(MyAppModel):
TEAM_CHOICES = (
('Unassigned', 'Unassigned'),
('National', 'National'),
('NSW', 'NSW'),
('SA', 'SA'),
)
Then enter this command:
python manage.py makemigrations
A migration will be generated:
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('my_app', '0102_previous_migrations'),
]
operations = [
migrations.AlterField(
model_name='my_client',
name='my_team',
field=models.CharField(choices=[('Unassigned', 'Unassigned'), ('ACT', 'ACT'), ('National', 'National'), ('NSW', 'NSW'), ('SA', 'SA')], default='Unassigned', max_length=255, verbose_name='My Team'),
),
]
Next to update all the existing values in the table now, referred here, enter this command to create an empty migration file:
python manage.py makemigrations --empty my_app
In the new migration file, put something like:
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2017-10-26 06:36
from __future__ import unicode_literals
from django.db import migrations
def set_unassigned(apps, schema_editor):
Client = apps.get_model('my_app', 'my_client')
for client in Client.objects.all():
client.account_team = 'Unassigned'
client.save()
class Migration(migrations.Migration):
dependencies = [
('my_app', '0104_client_team_update'),
]
operations = [
migrations.RunPython(set_unassigned),
]