Peewee circular foreign key dependencies exception - python

I'm trying to replicate Peewee example app using circular dependences as explained in the docs, despite the creator clearly states this is usually a bad idea. This is the code mainly copied from the docs:
from peewee import *
db = SqliteDatabase(None)
class BaseModel(Model):
class Meta:
database = db
class User(BaseModel):
username = CharField()
# Tweet has not been defined yet so use the deferred reference.
favorite_tweet = DeferredForeignKey('Tweet', null=True)
class Tweet(BaseModel):
message = TextField()
user = ForeignKeyField(User, backref='tweets')
db.init('twitter.db')
db.create_tables([User, Tweet])
User._schema.create_foreign_key(User.favorite_tweet) #Error
db.close()
I'm getting the an exception in the line commented with #Error. This line is needed, as explained in the docs:
When you call create_table we will again encounter the same issue. For
this reason peewee will not automatically create a foreign key
constraint for any deferred foreign keys.
To create the tables and the foreign-key constraint, you can use the
SchemaManager.create_foreign_key() method to create the constraint
after creating the tables.
This is the exception I get using Python 3.5.2:
Traceback (most recent call last):
File "/usr/local/lib/python3.5/dist-packages/peewee.py", line 2653, in execute_sql
cursor.execute(sql, params or ())
sqlite3.OperationalError: near "CONSTRAINT": syntax error
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "test3.py", line 23, in <module>
User._schema.create_foreign_key(User.favorite_tweet)
File "/usr/local/lib/python3.5/dist-packages/peewee.py", line 4930, in create_foreign_key
self.database.execute(self._create_foreign_key(field))
File "/usr/local/lib/python3.5/dist-packages/peewee.py", line 2666, in execute
return self.execute_sql(sql, params, commit=commit)
File "/usr/local/lib/python3.5/dist-packages/peewee.py", line 2660, in execute_sql
self.commit()
File "/usr/local/lib/python3.5/dist-packages/peewee.py", line 2451, in __exit__ reraise(new_type, new_type(*exc_args), traceback)
File "/usr/local/lib/python3.5/dist-packages/peewee.py", line 178, in reraise
raise value.with_traceback(tb)
File "/usr/local/lib/python3.5/dist-packages/peewee.py", line 2653, in execute_sql
cursor.execute(sql, params or ())
peewee.OperationalError: near "CONSTRAINT": syntax error

Sqlite does not support ALTER TABLE ADD CONSTRAINT -- so when you're using Sqlite you should omit the additional call to create_foreign_key().
There is a clear NOTE in the docs that says:
Because SQLite has limited support for altering tables, foreign-key constraints cannot be added to a table after it has been created.

Related

Abort connection when database is read-only (Flask/SQLAlchemy)

I am facing the following issue:
We have configured failover DB nodes for our staging environment. When testing, sometimes the failover happens and Flask keeps open connections to some nodes which are now read-only -- any write operation then fails:
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1277, in _execute_context
cursor, statement, parameters, context
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/engine/default.py", line 608, in do_execute
cursor.execute(statement, parameters)
File "/usr/local/lib/python3.7/site-packages/elasticapm/instrumentation/packages/dbapi2.py", line 210, in execute
return self.trace_sql(self.wrapped_.execute, sql, params)
File "/usr/local/lib/python3.7/site-packages/elasticapm/instrumentation/packages/dbapi2.py", line 244, in _trace_sql
result = method(sql, params)
psycopg2.errors.ReadOnlySqlTransaction: cannot execute DELETE in a read-only transaction
I'd like to detect this somehow and close the connection to these nodes, so that any write operation succeeds. Is this possible?
You can import that error class into your module, and then use it in a try-except block:
from psycopg2.errors import ReadOnlySqlTransaction
try:
# your main stuff here
except ReadOnlySqlTransaction:
# terminate the connection

How to fix incorrect SQLAlchemy metadata after migration

I have defined and created a SQLite database using SQLAlchemy, and added some data. This database has been working fine. However, I made a change to a column name in one the models ("User") and migrated this change using alembic. The current model looks like this, where the old name "analogy" was changed to "metaphor":
class User(Base):
__tablename__ = "user"
id = Column(Integer, primary_key=True)
username = Column(String(32), nullable=False, index=True, unique=True)
registered_on = Column(DateTime, index=True, default=datetime.now())
metaphor = Column(String(16))
The migration seemed to go fine, and I also doublechecked using the SQLite command line to confirm that the schema actually changed.
sqlite > .schema
CREATE TABLE "user" (
id INTEGER NOT NULL,
username VARCHAR(32) NOT NULL,
registered_on DATETIME,
metaphor VARCHAR(16),
PRIMARY KEY (id),
UNIQUE (wc_id)
);
CREATE UNIQUE INDEX ix_user_username ON user (username);
CREATE INDEX ix_user_registered_on ON user (registered_on);
But now when I try to query the table in Python, I get the following error, referencing the old column name and saying that there is no such column
>>> from background.database import db_session
>>> from data.models import User
>>> users = db_session.query(User).all()
Traceback (most recent call last):
File "/export/scratch/pt/power/lib/python3.5/site-packages/sqlalchemy/engine/base.py", line 1193, in _execute_context
context)
File "/export/scratch/pt/power/lib/python3.5/site-packages/sqlalchemy/engine/default.py", line 509, in do_execute
cursor.execute(statement, parameters)
sqlite3.OperationalError: no such column: user.analogy
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/export/scratch/pt/power/lib/python3.5/site-packages/sqlalchemy/orm/query.py", line 2843, in all
return list(self)
File "/export/scratch/pt/power/lib/python3.5/site-packages/sqlalchemy/orm/query.py", line 2995, in __iter__
return self._execute_and_instances(context)
File "/export/scratch/pt/power/lib/python3.5/site-packages/sqlalchemy/orm/query.py", line 3018, in _execute_and_instances
result = conn.execute(querycontext.statement, self._params)
File "/export/scratch/pt/power/lib/python3.5/site-packages/sqlalchemy/engine/base.py", line 948, in execute
return meth(self, multiparams, params)
File "/export/scratch/pt/power/lib/python3.5/site-packages/sqlalchemy/sql/elements.py", line 269, in _execute_on_connection
return connection._execute_clauseelement(self, multiparams, params)
File "/export/scratch/pt/power/lib/python3.5/site-packages/sqlalchemy/engine/base.py", line 1060, in _execute_clauseelement
compiled_sql, distilled_params
File "/export/scratch/pt/power/lib/python3.5/site-packages/sqlalchemy/engine/base.py", line 1200, in _execute_context
context)
File "/export/scratch/pt/power/lib/python3.5/site-packages/sqlalchemy/engine/base.py", line 1413, in _handle_dbapi_exception
exc_info
File "/export/scratch/pt/power/lib/python3.5/site-packages/sqlalchemy/util/compat.py", line 265, in raise_from_cause
reraise(type(exception), exception, tb=exc_tb, cause=cause)
File "/export/scratch/pt/power/lib/python3.5/site-packages/sqlalchemy/util/compat.py", line 248, in reraise
raise value.with_traceback(tb)
File "/export/scratch/pt/power/lib/python3.5/site-packages/sqlalchemy/engine/base.py", line 1193, in _execute_context
context)
File "/export/scratch/pt/power/lib/python3.5/site-packages/sqlalchemy/engine/default.py", line 509, in do_execute
cursor.execute(statement, parameters)
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such column: user.goal_period [SQL: 'SELECT user.id AS user_id, user.username AS user_username, user.registered_on AS user_registered_on, user.analogy AS user_analogy \nFROM user'] (Background on this error at: http://sqlalche.me/e/e3q8)
After tracing this error, it looks like the name change to the model is not reflected in the metadata imported from SQLAlchemy. So, SQLAlchemy is still using the metadata from the prior version of the table, while the actual database schema and the defined model have a different column name.
I've tried to delete all caches (.pyc, py_cache) to see if that was the source of the problem.
However, after doing this, there were still no changes to the metadata.
when I open a new interprer session and query the metadata, it shows the old schema, not the new one.
>>> from SQLAlchemy import MetaData
>>> metadata= MetaData()
>>> metadata.tables['user']
Table('user', MetaData(bind=None), Column('id', Integer(), table=<user>, primary_key=True, nullable=False), Column('username', String(length=32), table=<user>, nullable=False), Column('registered_on', DateTime(), table=<user>, default=ColumnDefault(datetime.datetime(2019, 6, 5, 12, 33, 57, 11763))), Column('goal_period', String(length=16), table=<user>, default=ColumnDefault('daily'))), schema=None)
Why is the metadata is not updated, and how do fix this problem?

got exception when do a loop input to database Python

So, I want to input data in multiple times with auto increment as primary key and return the primary key as the input result. so there's my code:
connectDB.py
import pymysql
class auth:
db = pymysql.connect("localhost","root","","rfid")
cursor = db.cursor()
def inputData(nama):
sql = "INSERT INTO auth (nama) VALUES ('%s');" % (nama)
try:
auth.cursor.execute(sql)
auth.db.commit()
result = auth.cursor.lastrowid
auth.db.close()
return result
except:
err = "Error: unable to fetch data"
auth.db.rollback()
auth.db.close()
return err
test.py
import re
import PyMySQL
from connectDB import auth
while True:
inputs2 = input("masukan nama: ")
hasil = auth.inputData(inputs2)
print(hasil)
so, when I do an input in the first time is success but when Itry to input again I got an error exception:
Traceback (most recent call last):
File "/home/pi/Desktop/learn/RFIDdatabase/connectDB.py", line 29, in inputData
auth.cursor.execute(sql)
File "/usr/local/lib/python3.4/dist-packages/pymysql/cursors.py", line 166, in execute
result = self._query(query)
File "/usr/local/lib/python3.4/dist-packages/pymysql/cursors.py", line 322, in _query
conn.query(q)
File "/usr/local/lib/python3.4/dist-packages/pymysql/connections.py", line 855, in query
self._execute_command(COMMAND.COM_QUERY, sql)
File "/usr/local/lib/python3.4/dist-packages/pymysql/connections.py", line 1071, in _execute_command
raise err.InterfaceError("(0, '')")
pymysql.err.InterfaceError: (0, '')
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "test.py", line 12, in <module>
hasil = auth.inputData(inputs2)
File "/home/pi/Desktop/learn/RFIDdatabase/connectDB.py", line 41, in inputData
auth.db.rollback()
File "/usr/local/lib/python3.4/dist-packages/pymysql/connections.py", line 792, in rollback
self._execute_command(COMMAND.COM_QUERY, "ROLLBACK")
File "/usr/local/lib/python3.4/dist-packages/pymysql/connections.py", line 1071, in _execute_command
raise err.InterfaceError("(0, '')")
pymysql.err.InterfaceError: (0, '')
so, What the exception cause?
Of course you would get an exception - cause you close the connection after executing a query:
auth.cursor.execute(sql)
auth.db.commit()
result = auth.cursor.lastrowid
auth.db.close() # < HERE
return result
You probably getting an "operation on a closed cursor" exception which is handled by your overly broad bare except clause (which is bad) - then - the roll back is initiated at auth.db.rollback() which fails with a not descriptive and understandable error.
Other issues:
I would make the db and cursor instance variables instead of class variables (differences)
don't "string format" your queries - proper parameterize them

peewee foreign key error

I am trying to create a simple model for my existing database with peewee.
The database that I'm working on is described in this paper.
I've generated a model with pwiz which works fine, however it didn't create foreign keys for me which enable joining. Therefore I edited the Model so it looks like this:
from peewee import *
database = MySQLDatabase('enron', **{'password': '...', 'user': 'root'})
class UnknownField(object):
pass
class BaseModel(Model):
class Meta:
database = database
class Employee(BaseModel):
email = CharField(db_column='Email_id', unique=True)
eid = PrimaryKeyField()
class Meta:
db_table = 'employeelist'
class Message(BaseModel):
mid = PrimaryKeyField()
sender = ForeignKeyField(Employee,
related_name='messages',
to_field='email') # was CharField() before my edit
class Meta:
db_table = 'message'
However when I try to run:
for message in Message.select():
print message.mid
I get an error:
Traceback (most recent call last):
File "DBModelEnron.py", line 62, in <module>
for message in Message.select():
File "/usr/local/lib/python2.7/dist-packages/peewee.py", line 2514, in __iter__
return iter(self.execute())
File "/usr/local/lib/python2.7/dist-packages/peewee.py", line 2507, in execute
self._qr = ResultWrapper(model_class, self._execute(), query_meta)
File "/usr/local/lib/python2.7/dist-packages/peewee.py", line 2203, in _execute
return self.database.execute_sql(sql, params, self.require_commit)
File "/usr/local/lib/python2.7/dist-packages/peewee.py", line 2833, in execute_sql
self.commit()
File "/usr/local/lib/python2.7/dist-packages/peewee.py", line 2688, in __exit__
reraise(new_type, new_type(*exc_value.args), traceback)
File "/usr/local/lib/python2.7/dist-packages/peewee.py", line 2825, in execute_sql
cursor.execute(sql, params or ())
File "/usr/lib/python2.7/dist-packages/MySQLdb/cursors.py", line 174, in execute
self.errorhandler(self, exc, value)
File "/usr/lib/python2.7/dist-packages/MySQLdb/connections.py", line 36, in defaulterrorhandler
raise errorclass, errorvalue
peewee.OperationalError: (1054, "Unknown column 't1.sender_id' in 'field list'")
I found a similar problem here, however I have a proper PrimaryKey defined.
Just add a db_column='' to your foreign keys:
sender = ForeignKeyField(Employee,
db_column='sender', # Added this.
related_name='messages',
to_field='email') # was CharField() before my edit

How do I connect to a MySQL Database in Python the right way?

update; hence to the kind and helpful replies of two great users here i did the following
hello dear bryn many thanks i erased the db cpan and runned the programme again see the results:
martin#linux-70ce:~/perl> python cpan_100.py
Traceback (most recent call last):
File "cpan_100.py", line 45, in <module>
user = User.create(name=entry["name"], cname=entry["cname"],
TypeError: string indices must be integers, not str
well this is somewhat difficult - why do i get these results!!?`
here the original posting
fairly new to python and to programming too.
I'm trying to connect to a MySQL database on Amazon's RDS using peewee and I can't get it to work. I'm new to databases so I'm probably doing something stupid, but this is what I'm trying: well i tried to get connection to a database in python with peewee but at a certain point the programme fails.
import urllib
import urlparse
import re
# import peewee
import json
from peewee import *
#from peewee import MySQLDatabase ('cpan', user='root',passwd='rimbaud')
db = MySQLDatabase('cpan', user='root',passwd='rimbaud')
class User(Model):
name = TextField()
cname = TextField()
email = TextField()
url = TextField()
class Meta:
database = db # this model uses the cpan database
User.create_table() #ensure table is created
url = "http://search.cpan.org/author/?W"
html = urllib.urlopen(url).read()
for lk, capname, name in re.findall('<b>(.*?)</b><br/><small>(.*?)</small>', html):
alk = urlparse.urljoin(url, lk)
data = { 'url':alk, 'name':name, 'cname':capname }
phtml = urllib.urlopen(alk).read()
memail = re.search('<a href="mailto:(.*?)">', phtml)
if memail:
data['email'] = memail.group(1)
# data = json.load('email') #your json data file here
for entry in data: #assuming your data is an array of JSON objects
user = User.create(name=entry["name"], cname=entry["cname"],
email=entry["email"], url=entry["url"])
user.save()
i get back the following results
martin#linux-70ce:~/perl> python cpan_100.py
Traceback (most recent call last):
File "cpan_100.py", line 27, in <module>
User.create_table() #ensure table is created
File "build/bdist.linux-i686/egg/peewee.py", line 3078, in create_table
File "build/bdist.linux-i686/egg/peewee.py", line 2471, in create_table
File "build/bdist.linux-i686/egg/peewee.py", line 2414, in execute_sql
File "build/bdist.linux-i686/egg/peewee.py", line 2283, in __exit__
File "build/bdist.linux-i686/egg/peewee.py", line 2406, in execute_sql
File "/usr/lib/python2.7/site-packages/MySQLdb/cursors.py", line 174, in execute
self.errorhandler(self, exc, value)
File "/usr/lib/python2.7/site-packages/MySQLdb/connections.py", line 36, in defaulterrorhandler
raise errorclass, errorvalue
peewee.OperationalError: (1050, "Table 'user' already exists")
martin#linux-70ce:~/perl>
if you can help me i would e very glad! Thanks for any and all help
greetings
It looks like it connects to your database properly but fails because the line:
User.create_table() #ensure table is created
tries to create a table then fails because a table already exists, hence the error message:
peewee.OperationalError: (1050, "Table 'user' already exists")
Try commenting it out:
#User.create_table()

Categories

Resources