Error creating tables in MySQL using peewee and FastAPI - mysql

I have below basic code where I am trying to create tables in food_delivery database using peewee ORM. I am receiving error as below:
AttributeError: 'str' object has no attribute 'safe_create_index'
My Code below:
DATABASE = 'food_delivery'
db = MySQLDatabase(
host='localhost',
user='my_user',
password='****',
database=DATABASE
)
class BaseModel(Model):
class Meta:
database = DATABASE
class Customer(BaseModel):
city = CharField()
customer = AutoField(column_name='customer_id')
email = CharField(column_name='email_id',unique=True)
first_name = CharField()
landmark = CharField()
last_name = CharField()
password = CharField()
phone_no = CharField(max_length=10)
pincode = IntegerField()
state = CharField()
class Meta:
table_name = 'customer'
database = DATABASE
def create_tables():
with db:
db.create_tables([Customer])
create_tables()
Can someone suggest what might be wrong with code?
Thanks!

I kept looking for issue and found that I had a logical syntax misplacement basically. Instead of database name under all the table definition in META, I actually had to pass connection instance of database instead of database name. But I wonder how inappropriate the thrown error is and its kind of impossible to fi seeing the error details. This requires much improvement by library maintainers.

Related

When attempting to loaddata - get error problem installing fixture

I am trying to load data from a db.json file I created (Sqlite db was the source). The original database is Sqlite, and I am try to migrate to Mysql.
Everything works fine under Sqlite. I get the following error:
django.db.utils.OperationalError: Problem installing fixture '/home/balh/blah/db.json': Could not load trackx_site.Segment(pk=1): (1054, "Unknown column 'program_id' in 'field list'")
It seems like the Mysql tables do not have the foreign key or something?.... The models look like this:
class Program(models.Model):
air_date = models.DateField(default="0000/00/00")
air_time = models.TimeField(default="00:00:00")
service = models.CharField(max_length=10)
block_time = models.TimeField(default="00:00:00")
block_time_delta = models.DurationField(default=timedelta)
running_time = models.TimeField(default="00:00:00",blank=True)
running_time_delta = models.DurationField(default=timedelta)
remaining_time =
models.TimeField(default="00:00:00",blank=True)
remaining_time_delta = models.DurationField(default=timedelta)
title = models.CharField(max_length=190)
locked_flag = models.BooleanField(default=False)
locked_expiration = models.DateTimeField(null=True,default=None,blank=True)
deleted_flag = models.BooleanField(default=False)
library = models.CharField(null=True,max_length=190,blank=True)
mc = models.CharField(max_length=64)
producer = models.CharField(max_length=64)
editor = models.CharField(max_length=64)
remarks = models.TextField(null=True,blank=True)
audit_time = models.DateTimeField(auto_now=True)
audit_user = models.CharField(null=True,max_length=32)
class Segment(models.Model):
class Meta:
ordering = ['sequence_number']
program = models.ForeignKey(Program,
on_delete=models.CASCADE,
related_name='segments', # link to Program
)
sequence_number = models.DecimalField(decimal_places=2,max_digits=6,default="0.00")
title = models.CharField(max_length=190, blank=True)
bridge_flag = models.BooleanField(default=False)
seg_length_time = models.TimeField()
seg_length_time_delta = models.DurationField(default=timedelta)
seg_run_time = models.TimeField(default="00:00:00",blank=True)
seg_run_time_delta = models.DurationField(default=timedelta)
seg_remaining_time = models.TimeField(default="00:00:00",blank=True)
seg_remaining_time_delta = models.DurationField(default=timedelta)
author = models.CharField(max_length=64,null=True,default=None,blank=True)
voice = models.CharField(max_length=64,null=True,default=None,blank=True)
library = models.CharField(max_length=190)
summary = models.TextField()
audit_time = models.DateTimeField(auto_now=True)
audit_user = models.CharField(null=True,max_length=32)
I also get a error when I attempt to run the server with the Mysql db settings. It will not allow me to add a record into the model and gives me an error complaining about program_id. I dont have anything named program_id that I am aware of.. (I looks through all the code).
It works fine when I run with Sqlite db settings. Adds programs and segments just fine.
Don't know what's wrong here. Any idea what I am doing wrong?
I figured out that my mysql database was not migrating correctly. Part of the problem was it was trying to do all the migrations, but since it was the inital build of the new database I did not need to have all the migrations (and somehow something was happening correctly in there). Removed all of the migrations, did initial makemigrations and migrate, and my Foreign Key was created correctly, no more problems.

insert_from over two databases

I try to move all rows from one database table (source) to another database (target). The source-DB is a local database while target-DB runs on another machine. I want to transfer rows between the two databases and found the Model.insert_from() method for that task. Unfortunately it does nothing and I can't find any reason for that.
The database model is:
databaseSource = MySQLDatabase('sourceDB', **{'host': 'localhost', 'user': 'local', 'password': ''})
databaseTarget = MySQLDatabase('targetDB', **{'host': 'externalserver', 'user': 'external', 'password': ''})
class BaseModelSource(Model):
class Meta:
database = databaseSource
class BaseModelTarget(Model):
class Meta:
database = databaseTarget
class UsersSource(BaseModelSource):
crdate = DateTimeField(constraints=[SQL("DEFAULT CURRENT_TIMESTAMP")])
description = TextField()
firstName = CharField(column_name='first_name')
class Meta:
table_name = 'users'
class UsersTarget(BaseModelTarget):
crdate = DateTimeField(constraints=[SQL("DEFAULT CURRENT_TIMESTAMP")])
description = TextField()
firstName = CharField(column_name='first_name')
class Meta:
table_name = 'users'
With that my task should run with:
import peewee
from dbmodels import *
dataQuery = UsersSource.select(
UsersSource.crdate,
UsersSource.description,
UsersSource.firstName)
insertQuery = UsersTarget.insert_from(dataQuery,[
UsersTarget.crdate,
UsersTarget.description,
UsersTarget.firstName]).execute()
The resulting MySQL-query is this and as you can see, the selected data is empty []:
('INSERT INTO `users` (`crdate`, `description`, `first_name`) SELECT `t1`.`crdate`, `t1`.`description`, `t1`.`first_name` FROM `users` AS `t1`', [])
When I run the SELECT query on my table it outputs:
SELECT `t1`.`crdate`, `t1`.`description`, `t1`.`first_name` FROM `users` AS `t1`;
2018-08-12 16:50:36 valid Heinz
2018-08-12 19:34:45 valid Hilde
2018-08-12 19:33:31 invalid Paul
I searched like hell but didn't find any hint, why my result is empty.
Does anybody know more or a better method?
Peewee cannot insert data between two different database servers/connections. If both databases are on the same server, however, you can use the "schema" Meta option to reference each database from a single connection, and do the INSERT FROM that way:
db = MySQLDatabase('my_db')
class UsersSource(Model):
crdate = DateTimeField(constraints=[SQL("DEFAULT CURRENT_TIMESTAMP")])
description = TextField()
firstName = CharField(column_name='first_name')
class Meta:
database = db
schema = 'source_db_name'
table_name = 'users'
class UsersTarget(Model):
crdate = DateTimeField(constraints=[SQL("DEFAULT CURRENT_TIMESTAMP")])
description = TextField()
firstName = CharField(column_name='first_name')
class Meta:
database = db
schema = 'dest_db_name'
table_name = 'users'
If the databases are on different servers, then you have no other option but to dump it and reload it.
If this is a one-off operation I recommend using mysqldump and then copying the file to the remote server and sourcing the dumped files with the mysql client.
If this needs to be a continual process look at MySQL replication.
To batch transfer it you'll need to iterate over the result set of the SELECT and put this into the INSERT statement as they are on different servers.

Python SQL Alchemy Multiple Databases - Binding Automap_Base

I am working through SQL Alchemy but struggling with how to structure the information from the docs into my project. I have two databases, my first will be used to store all new information from the python application. Where as the second database (DB1 in this case) is an existing database that I need to access information from. What is the right way to create this structure using SQLAlchemy?
I used the suggested BINDS method for multiple databases. This seems to be working.
class BaseConfig(object):
SECRET_KEY = "SO_SECURE"
DEBUG = True
SQLALCHEMY_DATABASE_URI = 'mssql+pyodbc://sa:funpassword#(localdb)\MSSQLLocalDB/Testing?driver=SQL+Server+Native+Client+11.0'
SQLALCHEMY_BINDS = {
'DB1': 'mssql+pyodbc://sa:$funpassword#ProdDB/DB1?driver=SQL+Server+Native+Client+11.0'
}
SQLALCHEMY_TRACK_MODIFICATIONS = True
This configuration seems to work okay because I am able to create new models in both of these databases using the code below. (This was done to just confirm that I was able to connect to both). db is my SqlAlchemy(app) initialization in my index.py file.
from index import app, db
#Test Writing To Default DB
class Test(db.Model):
id = db.Column(db.Integer(), primary_key=True)
employeeNum = db.Column(db.String(255), unique=False)
job = db.Column(db.String(255))
def __init__(self, employeeNum, job):
self.employeeNum = employeeNum
self.job = job
# Test Writing To DB1
class Test(db.Model):
__bind_key__ = 'DB1'
id = db.Column(db.Integer(), primary_key=True)
employeeNum = db.Column(db.String(255), unique=False)
job = db.Column(db.String(255))
def __init__(self, employeeNum, job):
self.employeeNum = employeeNum
self.job = job
I have tried many combinations using the table and automap_base from SQLAlchemy docs but this does not seem to work. I am not sure how I can use the bind_key of DB1 when I am trying to map existing tables.
from index import app, db
def loadSession():
Table('employee', db.metadata, Column('emp_num', Text, primary_key=True))
Base = automap_base(metadata=metadata)
Base.prepare()
employee = Base.classes.employee
emp = db.session.query(employee).all()
for i in emp:
print(i.data)
Thanks for any help you can provide.
for your DB1 with existing schema & data you could use reflection to get the tables mapped into sqlalchemy.
For your example it would probably look something like this:
from sqlalchemy.ext.automap import automap_base
from sqlalchemy import MetaData
from index import app, db
def loadSession():
# get a db engine object for DB1 configuration
engine = db.get_engine(bind='DB1')
# create a empty db Metadata object and bind it to DB1
database = MetaData(bind=engine)
# load the DB1 table/column structure into the Metadata object. This is quite a heavy operation and should optimally be done once on app setup and then the created automap_base can be stored / reused on demand until app shutdown
database.reflect(
bind=engine, views=True, autoload_replace=False
)
# create a python class structure out of the db metadata structure
auto_base = automap_base(metadata=database)
auto_base.prepare()
# create a db session for DB1
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
# get the reflected employees class from DB1. The employee table must exist in the database
employee = auto_base.classes.employee
# query DB1 with the new session object for all employee records
emp = db_session.query(employee).all()
for i in emp:
print(i.data)
# the following could also be substituted for the query without creating a session object:
for entry in employee.query.all():
print(entry)

saving an instance of a model with auto_now_add in Django returns error message Column 'xxx' cannot be null

I must be doing something very wrong or this error doesn't make any sense to me. I have an object Location:
class Location(models.Model):
class Meta:
db_table = 'location'
location_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=200)
state = models.CharField(max_length=200)
country = models.CharField(max_length=200)
apt_number = models.CharField(max_length=200, null=True, blank=True)
street_address = models.CharField(max_length=200)
city = models.CharField(max_length=200)
zip_code = models.IntegerField()
created = DateTimeField(auto_now_add=True)
here this is my code for inserting a new or updating an existing location record:
class LocationList(generics.ListCreateAPIView):
queryset = Location.objects.all()
serializer_class = LocationSerializer
def post(self, request, *args, **kwargs):
location_dict = request.data
if 'location_id' not in location_dict:
okStatus = status.HTTP_201_CREATED
else:
okStatus = status.HTTP_200_OK
location = Location(**location_dict)
location.save()
return Response(LocationSerializer(location).data, status=okStatus)
Inserts work fine, but everytime an update happens, I get the error "Column 'created' cannot be null". My online research seems to point me to the fact that this was a bug which has been long fixed. I expect the update to pass since the 'created' field was set to auto_now_add, which means Django should set that field once upon insert and leave it on any subsequent update. I do not know why Django is trying to set that column to null or any other value on update, because I expect Django to not update the column at all. I am using MySQL as database.
I think that your problem is in the " created column " try this steps :-
1) add null=True inside the created column
2) run :$ python"select version" manage.py makemigrations "appName or keep it empty"
3) run :$ python"V" manage.py sqlmegrate "aapName" " file version" >
check the file version in the app directory type it like this "0001"
4) run :$ python"V" manage.py migrate "appName"
after these steps ur db should be updated, last step is to remove (null=True from created column ) and start project.

Getting blank statement in django model charfield with mysql

I just migrated my django application from sqlite3 to mysql 5.1.41. I have a charfield in a model defined like this:
class HostData(models.Model):
Host = models.CharField(max_length=50, null=True)
HostStatus = models.CharField(max_length=200, null=True)
Alarm = models.BooleanField()
Everything works the same except HostStatus, which usually returns a string like "Up, waiting". In mysql, however, it is blank. I created my table with character set to utf-8. What am I doing wrong? Thanks in advance.
I can't see anything wrong with that model code.
How have you migrated your data over to MySQL? When you enter data via the django admin, does it enter data into the db?
If a view is entering this data, can you post the view code.
The issue was the way I was assigning the value to the model. I dont know why it worked well in sqlite, but it was bad coding anyways. This is what I was doing:
myarray = stdout_ssh
myobject = test.object.get(id=3)
myobject.Host = stdout_ssh[0]
myobject.HostStatus = status
status = stdout_ssh[1]
myobject.Alarm = False
myobject.save()
I changed this to:
myarray = stdout_ssh
myobject = test.object.get(id=3)
myobject.Host = stdout_ssh[0]
myobject.HostStatus = stdout_ssh[1]
myobject.Alarm = False
myobject.save()
And everything was ok.