SQLAlchemy - How to access column names from ResultProxy and write to CSV headers

2024/10/7 16:26:17

I am trying to use SQLAlchemy to establish a connection to a PostgreSQL Database, execute a SQL query and print the output of the file to a file in linux.

from sqlalchemy import create_engine
import yaml
import csvoutfile = open('/path/filename.csv', 'wb')
outcsv = csv.writer(outfile, delimiter='\t')with open('config.yml') as f:cfg = yaml.safe_load(f)username = cfg['credentials']['username']password = cfg['credentials']['password']host = cfg['credentials']['host'] port = cfg['credentials']['port']dbname = cfg['credentials']['dbname']engine = create_engine('postgresql://{}:{}@{}:{}/{}'.format(username, password, host, port, dbname))result = engine.execute("""select * from db.tablename """)# dump column titles (optional)outcsv.writerow(x[0] for x in result.description)# dump rowsoutcsv.writerows(result.fetchall())outfile.close()

However, I am getting the following error message - Traceback (most recent call last):File "", line 12, in AttributeError: 'ResultProxy' object has no attribute 'description'

If I comment the below command, I am successfully able to get the query result but without the headers. outcsv.writerow(x[0] for x in result.description)

Upon researching, I found the method - result._metadata.keys can generate the headers. However, it generates in some form of a list that I can't attach as header.

Please advise if there is any way to get the file header as well as the data into a csv file. Please consider the fact that I am beginner in Python while answering the above.

Answer

In this row in your example:

result = engine.execute("""select * from db.tablename """)

the variable result is pointed to an instance of the class sqlalchemy.engine.ResultProxy.

You want to get the column names to write to the first row of your csv file, and through inspecting your result object found result._metadata.keys which returns a regular python list of column names.

A convention in Python is that whenever an attribute, variable or method on an object is prefaced with an underscore (e.g. _metadata) that means it's not intended to be a public API, and the maintainers of the package may change their implementation in such a manner that breaks your code if you rely on these things (however unlikely for a stable library such as SQLAlchemy). Fortunately, in this case there is a documented public API for you to get what you need: ResultProxy.keys().

Remember that your result variable points to a ResultProxy instance, so you can access the keys() method on that to get the column names, e.g:

result.keys()

What happens when we try to write to your csv file:

outcsv.writerow(result.keys())

We get this exception:

TypeError: a bytes-like object is required, not 'str'

I'm going to assume that this is what you refer to when you say:

However, it generates in some form of a list that I can't attach asheader.

You can have a look at the open() API but the issue is that you've opened the file in such a manner that it expects binary data, not the strings that are returned from result.keys(). So if we change the line where you open your file to:

outfile = open('/path/filename.csv', 'w')

outfile.writerow will accept the result of result.keys().

Everything else should "just work".

Here is the code I used to test:

import csvfrom sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_baseBase = declarative_base()
engine = create_engine('sqlite:///:memory:', echo=False)
Session = sessionmaker(bind=engine)class Model(Base):__tablename__ = 'model'id = Column(Integer, primary_key=True)col1 = Column(String(10))col2 = Column(String(10))if __name__ == '__main__':# create some test dataBase.metadata.drop_all(bind=engine)Base.metadata.create_all(bind=engine)s = Session()data = dict(col1='a', col2='b')s.add_all(Model(**data) for _ in range(5))s.commit()s.close()# put the session away and work with the engineresult = engine.execute("select * from model")outfile = open('filename.csv', 'w', newline='')outcsv = csv.writer(outfile, delimiter='\t')outcsv.writerow(result.keys())outcsv.writerows(result.fetchall())

here's the contents of the csv:

id  col1    col2
1   a   b
2   a   b
3   a   b
4   a   b
5   a   b
https://en.xdnf.cn/q/70220.html

Related Q&A

Python Facebook API - cursor pagination

My question involves learning how to retrieve my entire list of friends using Facebooks Python API. The current result returns an object with limited number of friends and a link to the next page. How …

PyQt Irregularly Shaped Windows (e.g. A circular without a border/decorations)

How do I create an irregularly shaped window in PyQt?I found this C++ solution, however I am unsure of how to do that in Python.

default values for variable argument list in Python

Is it possible to set a default value for a variable argument list in Python 3?Something like:def do_it(*args=(2, 5, 21)):passI wonder that a variable argument list is of type tuple but no tuple is ac…

Python error: execute cannot be used while an asynchronous query is underway

How do I prevent the error “ProgrammingError: execute cannot be used while an asynchronous query is underway”? From the docs it says that I should use psycopg2.extras.wait_select if I’m using a cor…

Clearing Django form fields on form validation error?

I have a Django form that allows a user to change their password. I find it confusing on form error for the fields to have the *ed out data still in them.Ive tried several methods for removing form.dat…

How to watch xvfb session thats inside a docker on remote server from my local browser?

Im running a docker (That I built on my own), thats docker running E2E tests. The browser is up and running but I want to have another nice to have feature, I want the ability of watching the session o…

Flask WSGI application hangs when import nltk

I followed the instructions here to create a onefile flask-app deployed to apache2 with mod-wsgi on ubuntu. That all works fine when using the original flask app. However, when adding import nltk to th…

python append folder name to filenames in all sub folders

I am trying to append the name of a folder to all filenames within that folder. I have to loop through a parent folder that contain sub folders. I have to do this in Python and not a bat file.Example i…

When ruamel.yaml loads @dataclass from string, __post_init__ is not called

Assume I created a @dataclass class Foo, and added a __post_init__ to perform type checking and processing.When I attempt to yaml.load a !Foo object, __post_init__ is not called.from dataclasses import…

How is the python module search path determined on Mac OS X?

When a non built-in module is imported, the interpreter searches in the locations given by sys.path. sys.path is initialized from these locations (http://docs.python.org/library/sys.html#sys.path):the …