I'm newer to OOP in Python, and have been trying for awhile to use my database class database within another class.
How can I do so?
class database(object):
def connect_db(self):
try:
import sqlite3 as sqli
connection = sqli.connect('pw.db')
cur = connection.cursor()
except:
print("There was an error connecting to the database.")
I've been trying to like this, but it doesnt work:
import db_helper as dbh
class account_settings(object):
def create_account(self):
setting_username = input('\nUsername?\n')
setting_password = input('\nPassword?\n')
cur = db.connect_db()
with cur:
cur.execute('''
CREATE TABLE IF NOT EXISTS my_passwords(
id INTEGER PRIMARY KEY AUTOINCREMENT NULL,
password text UNIQUE
)
''')
try:
cur.execute('INSERT INTO my_passwords(password) VALUES(?)', (self.create_password(),) )
except:
print("Error occurred trying to insert password into db. Please retry")
c = account_settings()
c.create_account()
new error:
File "settings.py", line 30, in <module>
c.create_account()
File "settings.py", line 15, in create_account
with cur:
AttributeError: __exit__
You need to learn about variable scope. db.connect_db() creates a cursor connection with the name cur, but does not do anything with it; when that method finishes, the object is destroyed. In particular, it never makes it back to the create_account method.
There is a simple way to solve this: return the object back to the method, and use it there.
def connect_db(self):
...
cur = connection.cursor()
return cur
...
def create_account(self):
cur = db.connect_db()
with cur:
or even beter:
with db.connect_db()
Note that really, neither of these should be classes. Classes in Python are really only useful when you're keeping some kind of state, which isn't happening here. connect_db and create_account should just be standalone functions in their respective modules.
Related
I'm running into an error when I try to instantiate an object from a cursor in SQLite and I've exhausted my research and couldn't find a solution.
Premise: I cannot use SqlAlchemy or anything of that sorts.
Assumption: The database (SQLite) works, it contains a table named table_cars, and the table is populated with data in its single column: name.
So, I have a class lets say:
class Car():
def __init__(self, name):
self.name = name
#classmethod
def from_cursor(cls, c):
car = cls(c(0))
# this line breaks when called from the function below.
And I also have a db module, with the following function:
def get_cars_from_db():
sql = 'SELECT * FROM table_cars;'
conn = get_conn()
cur = conn.cursor()
cur.execute(sql)
data = cur.fetchall()
# at this point, if i print the cursor, I can see all data, so far so good.
cars = [Car.from_cursor(c) for c in data]
# the line above causes the code to break
return cars
The code breaks with the following error:
TypeError: 'tuple' object is not callable
What am I doing wrong here?
You can use cls(c[0]) or cls(*c) to unpack tuple to function arguments.
It's also worth to specify an exact order of your columns in query.
select name from table_cars
I am on a hobby project, working on a python mysql database, where I simple make the connection and perform some basic action, but when I run it give me reference error. My whole code looks like;
# My Mysql Library
import mysql.connector
#My Database class
class Database(object):
# Class Attributes
connection = None
cursor = None
TABLE_NAME = "customer"
# My constructor
def __init__(self):
""" This constructor is used to connect the database with my python application
and make the connection object and then create the cursor object with help
of it we create the table if not exists """
connection = mysql.connector.connect(
host="localhost",
user="root",
password="mypassword",
database="mydb"
)
# Initialize the cursor
self.cursor = connection.cursor()
# Create Individual Table
self.cursor.execute(f"""
CREATE TABLE IF NOT EXISTS {self.TABLE_NAME}(
cust_id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
cust_name VARCHAR(35),
cust_f_name VARCHAR(35),
cust_cno INTEGER(20) UNIQUE,
cust_address VARCHAR(50)
);
""")
def insert_data(self, name, f_name, cno, address):
""" This method is used to insert the value which is provided by user
With the help of GUI """
# self.cursor.execute(f"""
# INSERT INTO {Database.TABLE_NAME}(cust_name, cust_f_name, cust_cno, cust_address)
# VALUES (%, %, %, %, %)
# """, (name, f_name, cno, address))
# Insert Query
insert_query = f"""
INSERT INTO {Database.TABLE_NAME}(
cust_name, cust_f_name, cust_cno, cust_address
) VALUES (%, %, %, %);
"""
# Tuple of values which is to me inserted into the database
values = (name, f_name, cno, address)
# Execute the query and commit the data
self.cursor.execute(insert_query, values)
self.commit_data()
def commit_data(self):
""" This method is used to save all the data inside the db after data insertion"""
self.connection.commit()
def close_db(self):
""" This will close the database connection and cursor after performing everything"""
self.cursor.close()
self.connection.close()
# Main Body
db = Database()
db.insert_data("feezan", "noor", 552, "shaidu")
**But When I run it give the following error**
Traceback (most recent call last):
File "C:/Users/Feezan Khattak/OneDrive/Documents/My programming/Python Programming/PyQt5 Disgner/7- Data Entry With
Images/Database/MyDatabase.py", line 72, in
db.insert_data("feezan", "noor", 552, "shaidu")
File "C:/Users/Feezan Khattak/OneDrive/Documents/My programming/Python Programming/PyQt5 Disgner/7- Data Entry With
Images/Database/MyDatabase.py", line 58, in insert_data
self.cursor.execute(insert_query, values)
File "C:\Users\Feezan Khattak\AppData\Local\Programs\Python\Python37\lib\site-packages\mysql\connector\cursor_cext.py",
line 232, in execute
if not self._cnx:
ReferenceError: weakly-referenced object no longer exists
I will be highly appreciated your answers.
I am writing a script in python 3.x using mysqlconnector.
What I am trying to achieve right now is to check if there is a record inside my db which may be a duplicate to the one I am analyzing right now.
I came up with such code:
def fill_data(self, db_name, data):
cursor = self.cnx.cursor(buffered=True)
isDuplicate = cursor.execute(("SELECT destination FROM {0} WHERE destination = '{1}';")
.format(db_name, data['destination']))
print(cursor.statement)
self.commit()
print(isDuplicate is None)
Though I still get isDuplicate as None object. I tried to check via cursor.statement what statement is being passed to my db: it turned out that while in script I get None obj while passed in db that query works fine.
I also tried SELECT COUNT(1) FROM db_name which also gave me different results.
I am out of ideas: maybe you guys can help me out?
Update:
The solution that works for me was:
q = ("SELECT * FROM {0} WHERE destination = %s AND countryCode = %s AND prefix = %s")
.format(db_name)
cursor.execute(q, (data['destination'], data['country_code'], data['prefix']))
self.cnx.commit()
isDoubled = cursor.fetchone()
So at the end of the day it was all about fetching data from the cursor :)
Maybe the reason of your issue is the way you use execute() method.
Try to make some changes and see what is printed out:
def fill_data(self, db_name, data):
cursor = self.cnx.cursor(buffered=True)
q = 'SELECT count(*) FROM {} WHERE destination = %s'.format(db_name)
duplicate_count = cursor.execute(q, (data['destination'], )).fetchall()
print(duplicate_count)
Why should I provide query parameters this way? (article is on psql, but the core principles are the same as in mysql)
update
If you are still receiving "NoneType" object has no atribute "fetchall", then the error is probably here:
cursor = self.cnx.cursor(buffered=True)
Looks like you are not creating cursor at all. I can take a look at it if you post some code about cnx creation.
In Python mysqldb I could declare a cursor as a dictionary cursor like this:
cursor = db.cursor(MySQLdb.cursors.DictCursor)
This would enable me to reference columns in the cursor loop by name like this:
for row in cursor: # Using the cursor as iterator
city = row["city"]
state = row["state"]
Is it possible to create a dictionary cursor using this MySQL connector?
http://dev.mysql.com/doc/connector-python/en/connector-python-example-cursor-select.html
Their example only returns a tuple.
I imagine the creators of MySQL would eventually do this for us?
According to this article it is available by passing in 'dictionary=True' to the cursor constructor:
http://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursordict.html
so I tried:
cnx = mysql.connector.connect(database='bananas')
cursor = cnx.cursor(dictionary=True)
and got:
TypeError: cursor() got an unexpected keyword argument 'dictionary'
and I tried:
cnx = mysql.connector.connect(database='bananas')
cursor = cnx.cursor(named_tuple=True)
and got:
TypeError: cursor() got an unexpected keyword argument 'named_tuple'
and I tried this one too: cursor = MySQLCursorDict(cnx)
but to no avail. Clearly I'm on the wrong version here and I suspect we just have to be patient as the document at http://downloads.mysql.com/docs/connector-python-relnotes-en.a4.pdf suggests these new features are in alpha phase at point of writing.
A possible solution involves subclassing the MySQLCursor class like this:
class MySQLCursorDict(mysql.connector.cursor.MySQLCursor):
def _row_to_python(self, rowdata, desc=None):
row = super(MySQLCursorDict, self)._row_to_python(rowdata, desc)
if row:
return dict(zip(self.column_names, row))
return None
db = mysql.connector.connect(user='root', database='test')
cursor = db.cursor(cursor_class=MySQLCursorDict)
Now the _row_to_python() method returns a dictionary instead of a tuple.
I found this on the mysql forum, and I believe it was posted by the mysql developers themselves. I hope they add it to the mysql connector package some day.
I tested this and it does work.
UPDATE: As mentioned below by Karl M.W... this subclass is no longer needed in v2 of the mysql.connector. The mysql.connector has been updated and now you can use the following option to enable a dictionary cursor.
cursor = db.cursor(dictionary=True)
This example works:
cnx = mysql.connector.connect(database='world')
cursor = cnx.cursor(dictionary=True)
cursor.execute("SELECT * FROM country WHERE Continent = 'Europe'")
print("Countries in Europe:")
for row in cursor:
print("* {Name}".format(Name=row['Name']
Keep in mind that in this example, 'Name' is specific to the column name of the database being referenced.
Also, if you want to use stored procedures, do this instead:
cursor.callproc(stored_procedure_name, args)
result = []
for recordset in cursor.stored_results():
for row in recordset:
result.append(dict(zip(recordset.column_names,row)))
where stored_procedure_name is the name of the stored procedure to use and args is the list of arguments for that stored procedure (leave this field empty like [] if no arguments to pass in).
This is an example from the MySQL documentation found here: http://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursordict.html
Using Python 3.6.2 and MySQLdb version 1.3.10, I got this to work with:
import MySQLdb
import MySQLdb.cursors
...
conn = MySQLdb.connect(host='...',
<connection info>,
cursorclass=MySQLdb.cursors.DictCursor)
try:
with conn.cursor() as cursor:
query = '<SQL>'
data = cursor.fetchall()
for record in data:
... record['<field name>'] ...
finally:
conn.close()
I'm using PyCharm, and simply dug into the MySQLdb modules connections.py and cursors.py.
I had the same problem with the default cursor returning tuples with no column names.
The answer is here:
Getting error while using MySQLdb.cursors.DictCursor in MYSQL_CURSORCLASS
app.config["MYSQL_CURSORCLASS"] = "DictCursor"
I'm fairly new to Python. And this is my first class:
import config # Ficheiro de configuracao
import twitter
import random
import sqlite3
import time
import bitly_api #https://github.com/bitly/bitly-api-python
class TwitterC:
def logToDatabase(self, tweet, timestamp):
# Will log to the database
database = sqlite3.connect('database.db') # Create a database file
cursor = database.cursor() # Create a cursor
cursor.execute("CREATE TABLE IF NOT EXISTS twitter(id_tweet INTEGER AUTO_INCREMENT PRIMARY KEY, tweet TEXT, timestamp TEXT);") # Make a table
# Assign the values for the insert into
msg_ins = tweet
timestamp_ins = timestamp
values = [msg_ins, timestamp_ins]
# Insert data into the table
cursor.execute("INSERT INTO twitter(tweet, timestamp) VALUES(?, ?)", values)
database.commit() # Save our changes
database.close() # Close the connection to the database
def shortUrl(self, url):
bit = bitly_api.Connection(config.bitly_username, config.bitly_key) # Instanciar a API
return bit.shorten(url) # Encurtar o URL
def updateTwitterStatus(self, update):
short = self.shortUrl(update["url"]) # Vou encurtar o URL
update = update["msg"] + short['url']
# Will post to twitter and print the posted text
api = twitter.Api(consumer_key=config.consumer_key,
consumer_secret=config.consumer_secret,
access_token_key=config.access_token_key,
access_token_secret=config.access_token_secret)
status = api.PostUpdate(update) # Fazer o update
msg = status.text # Vou gravar o texto enviado para a variavel 'msg'
# Vou gravar p a Base de Dados
self.logToDatabase(msg, time.time())
print msg # So p mostrar o texto enviado. Comentar esta linha de futuro.
x = TwitterC()
x.updateTwitterStatus({"url": "http://xxxx.com/?cat=49", "msg": "Searching for some ....? "})
My question. What should I refactor in this ugly code(I think)?
For example. When I try do duplicate a Twitter Update I got this error:
Traceback (most recent call last):
File "C:\Users\anlopes\workspace\redes_sociais\src\twitterC.py", line 42, in <module>
x.updateTwitterStatus({"url": "http://xxx.com/?cat=49", "msg": "Searching for some ...? "})
File "C:\Users\anlopes\workspace\redes_sociais\src\twitterC.py", line 35, in updateTwitterStatus
status = api.PostUpdate(update) # Fazer o update
File "C:\home_python\python_virtualenv\lib\site-packages\twitter.py", line 2549, in PostUpdate
self._CheckForTwitterError(data)
File "C:\home_python\python_virtualenv\lib\site-packages\twitter.py", line 3484, in _CheckForTwitterError
raise TwitterError(data['error'])
twitter.TwitterError: Status is a duplicate.
How can I for example catch this error in Python?
Some clues needed.
Best Regards,
As the output states clearly, your code is raising a twitter.TwitterError exception. You catch it like this:
try:
# yadda yadda
except twitter.TwitterError:
# exception code
else:
# happy flow code, optionally.
finally:
# must-run code, optionally
Now, when you are writing your first class and don't know how to catch exceptions in a language, you don't try to fetch twitter updates and save them in a database. You print "Hello World!". Go do a tutorial :D.
One possibility would be to write a function that connects to and disconnects from the database and during the connection time does some stuff. It could look something like this:
class DBFactory(object):
def DBConnection(self, Func, args):
database = sqlite3.connect('database.db') # Create a database file
cursor = database.cursor() # Create a cursor
Func(cursor, args)
database.commit() # Save our changes
database.close() # Close the connection to the database
Now the Func and args parameter actually do the interaction to the database. For example something like this:
def CreateTable(cursor, args):
cursor.execute("CREATE TABLE IF NOT EXISTS {0};".format(args)) # Make a table
Now if you wish to create a table you simple have to make this call:
f = DBFactory()
f.DBConnection(CreateTable, "twitter(id_tweet INTEGER AUTO_INCREMENT PRIMARY KEY, tweet TEXT, timestamp TEXT)"
You can proceed similarly with other interactions to the database for example inserting or deleting entries. Each time calling the DBConnection method. This should modularize your class a little better. At least in my opinion.
Please note that I did not give this code above a try, so there might be a typo in there, but I hope you get the idea. I hope this helped ya
Cherio
Woltan
The first thing to refactor is to get this code out of a class. It has absolutely no need to be in one. This should be a module, with standalone functions.
Edit to add more explanation In Python, most code is grouped naturally into modules. Classes are mainly useful for when you will need discrete instances, each with their own data. This is not the case here - you are just using the class as a placeholder for related code. That's what modules are for.
If, for example, you wanted to model an individual Tweet, which knew about its own content and how to save itself into a database, that would indeed be a good use of OOP. But "stuff that's related to Twitter" is not a class, it's a module.