Django: How do I perform database introspection with multiple databases? - python

I have code that works for getting models and fields from a Django database. However, it only works on the default database.
This function wants a database name, and I'd like to get the tables and fields for that database.
def browse_datasource(request, dbname):
table_info = []
# This is what I'd /like/ to be able to do, but it doesn't work:
# tables = connections[dbname].introspection.table_names()
tables = connection.introspection.table_names()
found_models = connection.introspection.installed_models(tables)
for model in found_models:
tablemeta = model._meta
columns = [field.column for field in model._meta.fields]
table_info.append([model.__name__, columns])
How can I perform introspection on the non-default databases? Is there a correct way to get connection.introspection for a database with the name "example", for example?

I found the solution. The trick is getting the database connection from the connections list, then getting a cursor and passing that to introspection.table_names, like so:
table_info = []
conn = connections[dbname]
cursor = conn.cursor()
tables = conn.introspection.table_names(cursor)
found_models = conn.introspection.installed_models(tables)
for model in found_models:
tablemeta = model._meta

Related

How to test functions that interacts with database

I have the functions that performs some CRUD operations with database like this:
def get_user_by_id(user_id):
db = get_db()
cursor = db.cursor(cursor_factory=extras.DictCursor)
cursor.execute(
'SELECT * FROM users WHERE id = %s',
(user_id, )
)
user = cursor.fetchone()
cursor.close()
return user
I want to test it with pytest, but don't know the right way to do it.
For example to get user data from database I should first create it and then call tested function. But should I call my create_user() function at setup and then call tested get_user_by_id()? Or it would be better to populate database with some test data and then use it? Should I test this kind of functions at all?

create a copy of all tables with its key and other constraints from sql-server database to another database

I try to copy the sql-server's table with its keys and other constraints through SQLAlchemy in python
`from sqlalchemy import *
DATABASE_CONN = f'mssql://#{SERVER}/{DATABASE}?driver={DRIVER}'
DATABASE_CONN2 = f'mssql://#{SERVER}/{DB2}?driver={DRIVER}'
engine = create_engine(DATABASE_CONN)
engine2 = create_engine(DATABASE_CONN2)
connection = engine.connect() connection2 = engine2.connect()
metadata = MetaData() table = Table('table_name', metadata, autoload=True, autoload_with=engine) table.create(engine2)
ERROR:
sqlalchemy.exc.NoSuchTableError: table_name
if i putting the specific table name instead of 'table_name' then it create that table in new databse but i have to do it for all table so any technique to resolve this issue and make the copy of all table with its keys and other constraint at one go.
You recreate all the table schema from one database in a second by reflecting the first into a metadata object and then creating the tables in the second:
meta = MetaData()
meta.reflect(engine)
meta.create_all(engine2)
It's possible to control precisely which tables get reflected - review the docs for Reflecting Database Objects and metadata.reflect.

Do i need to call create tables every time in peewee?

I working in a project in which i have different projects with the same database architecture,
so i used peewee Model in which:
dynamic_db = SqliteDatabase(None)
class BaseModel(Model):
class Meta:
database = dynamic_db
class KV (BaseModel):
key = TextField()
value = IntegerField()
And whenever i new project is created i will call a function
dynamic_db.init(r'{}\database.db'.format(ProjectName.upper()))
dynamic_db.connect()
dynamic_db.create_tables([KV])
dynamic_db.close()
The problem is that once this database is created, i can't access with peewee.
When i try to create a record:
KV.create(key = 'Saul', value = 123)
I get this error:
peewee.InterfaceError: Error, database must be initialized before opening a connection.
I would appreciate any help or cookbook for peewee.
I believe something is incorrect, either in your question description, or in the error you are receiving. The call you are making to .init() is what initializes the database. After that, you should have no problems using it.
Full example which works fine:
from peewee import *
db = SqliteDatabase(None)
class Base(Model):
class Meta:
database = db
class KV(Base):
key = TextField()
value = IntegerField()
db.init('foo.db') # database is now initialized
db.connect()
db.create_tables([KV]) # no problems.
db.close()
I was finally able to create a record.
I didn't mention that i was trying to create them in another file, but the procedure is the same as the one coleifer posted on the answer.
The file in which i create the peewee models is databases.py, so in the other file i do the following:
import databases
databases.db.init('foo.db')
databases.KV.create(name = 'Saul', value= 123)
Thanks!

Querying a for table not defined in models Sqlalchemy

I have this table in my database (using Posgresql and Sqlalchemy) called "participants".
In my models.py I want to access the participant's records. Since participants is not in my models.py and resides as a table in my db, when I do query = db.session.query('participants').order_by('name').all() I get an error:
ProgrammingError: (ProgrammingError) column "participants" does not exist
LINE 1: SELECT participants ORDER BY name
^
What can I do to retrieve this information?
Like the comment on the original post, did something like:
query = db.engine.execute('select * from participants order by name')
This doesn't give it in the same format as the query so I could use it for what I needed (a dictionary output, and a format for web), so I did:
partner_list = []
for record in query:
record_dict = dict(record)
partner_list.append(record_dict)

Using the SQL initialization hook with ManytoManyField

I'm fairly new to Django and I'm trying to add some 'host' data to 'record' using django's hook for using SQL to initialise (a SQL file in lowercase in the app folder & sql subfolder)
Here's the models:
class Record(models.Model):
species = models.TextField(max_length = 80)
data=models.TextField(max_length = 700)
hosts = models.ManyToManyField('Host')
class Host(models.Model):
hostname = models.TextField()
I've used a ManyToManyField as each record should be able to have multiple hosts, and hosts should be 'reusable': ie be able to appear in many records.
When I'm trying to insert via SQL I have
INSERT INTO myapp_record VALUES ('Species name', 'data1', XYZ);
I'm not sure what to put for XYZ (the ManytoMany) if I wanted hosts 1, 2 and 3 for example
Separating them by commas doesn't work obviously, and I tried a tuple and neither did that.
Should I be trying to insert into the intermediary table Django makes? Does that have a similar hook to the one I'm using? If not, how can I execute SQL inserts on this table?
The use of initial SQL data files is deprecated. Instead, you should be using a data migration, which might look something like this:
from django.db import models, migrations
def create_records(apps, schema_editor):
# We can't import the Person model directly as it may be a newer
# version than this migration expects. We use the historical version.
Record = apps.get_model("yourappname", "Record")
Host = apps.get_model("yourappname", "Host")
host1 = Host.objects.get(hostname='host1')
record = Record.objects.create(name='Species name', data='Data')
record.hosts.add(host1)
...etc...
class Migration(migrations.Migration):
dependencies = [
('yourappname', '0001_initial'),
]
operations = [
migrations.RunPython(create_records),
]

Categories