I created two tables for my truck scheduling application:
class appts_db(db.Model):
id = db.Column(db.Integer, primary_key=True)
carrier = db.Column(db.String(100))
material = db.Column(db.String(10))
pickup_date = db.Column(db.String(10))
class carriers_db(db.Model):
carrier_id = db.Column(db.Integer, primary_key=True)
carrier = db.Column(db.String(100))
phone_number = db.Column(db.String(15))
How can I rename the column carrier to carrier_name in both tables to make it more clear what the columns contain. I tried using the command prompt
>python3
>db.create_all()
But the column name doesn't update. Is there some command that I'm missing that can update the column name in the db?
(1.) This seems to be a question about "how to migrate a single table?", twice. That is, whatever answer works for appts_db will also need to be applied to carriers_db -- I don't see a FK relation so I think most technical solutions would need to be manually told about that 2nd rename.
(2.) There are many nice "version my schema!" approaches, including the usual ruby-on-rails approach. Here, I recommend alembic. It takes some getting used to, but once implemented it lets you roll forward / roll back in time, and table schemas will match the currently-checked-out source code's expectations. It is specifically very good at column renames.
(3.) The simplest possible thing you could do here is a pair of DROP TABLE and then re-run the db.create_all(). The existing table is preventing create_all from having any effect, but after the DROP it will do just what you want. Of course, if you care about the existing rows you will want to tuck them away somewhere before you get too adventurous.
I ended up using DB Browser for SQLite (I had downloaded it previously) and ran this code in the "Execute SQL" tab:
ALTER TABLE carriers_db
RENAME COLUMN carrier TO carrier_name;
Related
I'm in the middle of developing a small site in Python. I use flask and venv.
I am currently in the middle of writing the data base and here is one of my tables:
class Message(db.Model):
message_id = db.Column(db.Integer, primary_key=True)
session_id = db.Column(db.String(30), unique=True)
application_id = db.Column(db.Integer)
participants = db.Column(db.Array())
content = db.Column(db.String(200))
The problem is in line 5:
"Array".
There is no such variable type.
I want to create a list of message recipients. Is there an Array or List variable type in SQlite?
If so, what is and how is it used?
And if not, how can I make a list of recipients anyway?
Anyone know?
Thank you very much!
SQLite does not support arrays directly. It only does Ints, Floats and Text. See here the type it supports.
To accomplish what you need, you have to use a custom encoding, or use an FK, i.e. create another table, where each item in the array is stored as a row. This would get tedious in my opinion.
Alternatively, it can be done in SQLAlchemy and you will want to have a look at the PickleType:
array = db.Column(db.PickleType(mutable=True))
Please note that you will have to use the mutable=True parameter to be able to edit the column. SQLAlchemy will detect changes automatically and they will be saved as soon as you commit them.
Also, have a look at the ScalarListType in SQLAlchemy for saving multiple values in column.
Update:
In SqlAlchemy You can use array column.
For example:
class Example(db.Model):
id = db.Column(db.Integer, primary_key=True)
my_array = db.Column(db.ARRAY(db.Integer())
# You can easily find records:
# Example.my_array.contains([1, 2, 3]).all()
# You can use text items of array
# db.Column(db.ARRAY(db.Text())
Update: This doesn't work in SQLite, SQLAlchemy's ARRAY type is for Postgres databases only. The best alternative for most people would be something involving JSON or switching to Postgres if possible. I'll be attempting JSON myself. credit to the replier in the comments.
I'm playing with django (I'm a quite new beginner) and while surfing the web I read it could be possible to keep our internal camelCase naming conventions inside the mySQL database and also for the models' name inside models.py
Well, after some days I can conclude it's better to leave things as they were designed and use the standard output generated by inspectdb without any change to its code (I removed the .lower() functions :-) )
Anyhow, just out of curiosity, I would appreciate if somebody can explain me why what follows is not working. Briefly, it seems to me that the code responsible for the migration is not checking correctly(?) if a column name is already inside the database, or at least it does its comparison in case-sensitive manner. Is that by design?
I'm using this guide from the internet https://datascience.blog.wzb.eu/2017/03/21/using-django-with-an-existinglegacy-database/
The mysql is running with the option " --lower-case-table-names=0" and the collation is case-insensitive.
Inside the models.py I have this
class City(models.Model):
id = models.AutoField(db_column='ID', primary_key=True)
name = models.CharField(db_column='Name', max_length=35)
countrycode = models.ForeignKey(Country, db_column='CountryCode')
district = models.CharField(db_column='District', max_length=20)
population = models.IntegerField(db_column='Population', default=0)
def __str__(self):
return self.name
class Meta:
managed = True
db_table = 'city'
verbose_name_plural = 'Cities'
ordering = ('name', )
if I change the reference 'db_column' to db_column='countryCode' (note the lower "c" ) and I run
./manage.py migrate --database world_data --fake-initial worlddata
I get errors saying 'django.db.utils.OperationalError: (1050, "Table 'city' already exists")'
and the problem arises only using the --fake-initial option
After analyzing "...django/db/migrations/executor.py" I found those line that check if a column is already inside the existing
column_names = [
column.name for column in
self.connection.introspection.get_table_description(self.co$
]
if field.column not in column_names:
return False, project_state
here, for what I understand, there is no case sensitive comparison so the "countryCode" column is not found inside "column_names":
-> if field.column not in column_names:
(Pdb) field.column
'countryCode'
(Pdb) column_names
['ID', 'Name', 'CountryCode', 'District', 'Population']
First of all I'd like to congratulate you on being so through with your first question! Many older contributors don't go into as much depth as you.
So first let's get things straight. You mention that --lower-case-table-names=0 is enabled but collation is case insensitive. From the docs I see that the option forces case sensitivity for table names. I might just be reading it wrong but it looks like you're saying everything should be case insensitive. Also collation usually refers to the data itself, not column names in case you're unaware.
That said as far as I know, all databases treat column names case-insensitively (I just tested in SQLite) so you might have just uncovered a bug in Django! I looked through the history of the file, and in the 5-odd years that code has existed I guess no one ran into this issue. It's understandable since usually people either a) just let django create the db from scratch and thus everything is in sync, or b) they use inspectdb to generate the code with the right case for the columns.
It looks like you were just playing around so I don't think you are looking for a specific solution. Perhaps the next step is to file a bug ;)? From what I see there would be no downside to adding case-insensitive comparison there, but the guys working on Django 24/7 may have a different opinion.
I want to create 200+ tables using declarative base on the fly. I learnt it's not possible, so my idea was to create a common table and rename it 200+ times.
class Movie(Base):
id = Column(Integer, primary_key=True)
title = Column(String)
release_date = Column(Date)
name=Column(String)
__tablename__ = 'titanic'
def __init__(self, newname,title, release_date):
self.title = title
self.release_date = release_date
What is the code to change the table name from "titanic" to "wild"?
In Postgresql it is
ALTER TABLE table_name
RENAME TO new_table_name;
I am not finding a solution in sqlalchemy.
There are no foreign keys to this table.
The objective of this question is to rename an existing table thru a solution (if) available in sqlalchemy, not in a purely python way (as mentioned in the other question).
The easiest way to rename a table is to create a new table, dumping the data into it with an INSERT INTO statement.
More from the web:
You must issue the appropriate ALTER statements to your database to change the name of the table. As far as the Table metadata itself, you can attempt to set table.name = 'newname', and re-place the Table object within metadata.tables with its new name, but this may have lingering side effects regarding foreign keys that reference the old name. In general, the pattern is not supported - its intended that a SQLAlchemy application runs with a fixed database structure (only new tables can be added on the fly).
(Source)
Say I have 3 models in Django
class Instrument(models.Model):
ticker = models.CharField(max_length=30, unique=True, db_index=True)
class Instrument_df(models.Model):
instrument = models.OneToOneField(
Instrument,
on_delete=models.CASCADE,
primary_key=True,
)
class Quote(models.Model):
instrument = models.ForeignKey(Instrument, on_delete=models.CASCADE)
I just want to query all Quotes that correspond to an instrument of 'DF' type. in SQL I would perform the join of Quote and Instrument_df on field id.
Using Django's ORM I came out with
Quote.objects.filter(instrument__instrument_df__instrument_id__gte=-1)
I think this does the job, but I see two drawbacks:
1) I am joining 3 tables, when in fact table Instrument would not need to be involved.
2) I had to insert the trivial id > -1 condition, that holds always. This looks awfully artificial.
How should this query be written?
Thanks!
Assuming Instrument_df has other fields not shown in the snippet (else this table is just useless and could be replaced by a flag in Instrument), a possible solution could be to use either a subquery or two queries:
# with a subquery
dfids = Instrument_df.objects.values_list("instrument", flat=True)
Quote.objects.filter(instrument__in=dfids)
# with two queries (can be faster on MySQL)
dfids = list(Instrument_df.objects.values_list("instrument", flat=True))
Quote.objects.filter(instrument__in=dfids)
Whether this will perform better than your actual solution depends on your db vendor and version (MySQL was known for being very bad at handling subqueries, don't know if it's still the case) and actual content.
But I think the best solution here would be a plain raw query - this is a bit less portable and may require more care in case of a schema update (hint: use a custom manager and write this query as a manager method so you have one single point of truth - you don't want to scatter your views with raw sql queries).
I'm trying out flask-mongoengine and mongohq and I'm having some difficulty getting it to declare my documents correctly.
I've declaed a db document like so:
class numbers(nodb.Document):
numbers = nodb.StringField(required=True)
simple_date = nodb.DateTimeField(required=True, unique=True, primary_key=True)
date = nodb.DateTimeField(default=datetime.now, required=True)
now when I add an entry to the document it's not taking my _id or even acknowledging that I've put in the unique or primary_key requirement.
test = numbers(
_id=datetime.strptime(currentdate, "%m/%d/%Y").date(),
simple_date=datetime.strptime(currentdate, "%m/%d/%Y").date(),
numbers='12345'
)
test.save()
now if I do those lines again, it creates another identical entry in the db and the requirements on simple_date appear to be ignored. Not sure if I'm hitting a bug here or just doing something wrong?
Mongoengine must create indexes if collection not exists yet. Mongoengine do not take care about data migration. So if you at first created collection without index and next describe index in model then index not created automatically. For your case you must create indexes manually or try drop your numbers collection only for development database when data not necessary.