Python 函数在SQLAlchemy中构建表列和关系

Python 函数在SQLAlchemy中构建表列和关系,python,sqlite,sqlalchemy,Python,Sqlite,Sqlalchemy,我试图使用SQLAlchemy组合一个函数来构建表及其关系。问题是,我正在处理具有许多列和许多外键的表。有些关系是多对一的,但有些关系是多对多的。由于有许多方面对数据库的结果感兴趣,因此将来肯定会添加更多的列。因此,能够从函数构建表是可取的。这是我环顾四周几天后得到的: from sqlalchemy import Column, String, Integer, ForeignKey, MetaData, Table, create_engine from sqlalchemy.orm imp

我试图使用SQLAlchemy组合一个函数来构建表及其关系。问题是,我正在处理具有许多列和许多外键的表。有些关系是多对一的,但有些关系是多对多的。由于有许多方面对数据库的结果感兴趣,因此将来肯定会添加更多的列。因此,能够从函数构建表是可取的。这是我环顾四周几天后得到的:

from sqlalchemy import Column, String, Integer, ForeignKey, MetaData, Table, create_engine
from sqlalchemy.orm import relationship, backref, sessionmaker
from sqlalchemy.ext.declarative import declarative_base


db = "alchemy_database_test.db"
db_memory = 'sqlite:///' + db
engine = create_engine(db_memory)

Base = declarative_base()
post_meta = MetaData(bind=engine)

#Example of names to build tables and columns
col_names = ['productID', 'productShortName', 'productName','quantity']
col_types = [Integer, String, String, Integer]
primary_key_flags = [True, False, False, False]
nullable_flags = [False, False, False, False]

# Lists to build relationship statements
## relationship name
name_of_target = ['platforms','regions','references', 'protocols']
# name of the target table containing the foreign ID to link
name_of_target_table = ['platform','region','reference','protocol']

# Since I am using a single list of foreign keys, and many-to-one has a different 
# syntax compared to many-to-many relationships (or so I think), I'm building two
# lists and filling in with None to make them the same size and iterate 
# simultaneously through both

## for many to one relationships
name_of_target_column = ['platformID','regionID',None,None]
## for many to many relationships
name_of_column_m2m = [None,None,'referenceID','protocolID']

def create_sqltable(post_meta,name,col_names,col_types,primary_key_flags,
   link_tos=[], link_to_table=[], link_to=[], many_to_many=[]):

   test = Table(name, post_meta,

               #here i'm creating the columns and assigning primary key
               #and auto-increment, if needed. This works well.

               *(Column(c_names, c_types,
                       primary_key=primary_key_flag,
                       autoincrement=primary_key_flags,
                       nullable=nullable_flag)
               for c_names,
                   c_types,
                   primary_key_flag,
                   nullable_flag in zip(col_names,
                                           col_types,
                                           primary_key_flags,
                                           nullable_flags)),

               #I'm trying to do the same with the relationship statement
               # building a statement for each foreign key by assigning
               # the name of the relationship, the target table, and 
               # either a 'backref' or a 'secondary' argument depending 
               # if it is a maney-to-one or a many-to-many relationship

               *(relationship(lk_tos, #name of the relationship
                       lk_to_table, #name of the target table
                       secondary=mny_to_mny, #name of the column in the target
                                             # table (many2many relationship)
                       backref=lk_to_col, #name of the column in the target 
                                          # table (many2one relationship)
                       cascade="all,delete")
               for lk_tos, # name of relationship
                   lk_to_table, # name of target table
                   lk_to_col, # name of column in target table (many2one)
                   mny_to_mny in zip(link_tos,
                                           link_to_table,
                                           link_to,
                                           many_to_many))) # column in target table(many2many)
   test.create()

#calling the function with the lists declared earlier
create_sqltable(post_meta,'table_name',col_names, col_types, primary_key_flags,
       name_of_target, name_of_target_table, name_of_target_column, name_of_column_m2m)
我得到以下错误:


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
~/OneDrive - 3M/Projects/Searchable database/Code/Relational-Database/database_wd_v3.py in 
      59     ['table1','table2','customer','lamp','crystals'],
      60     ['table1ID','table2ID','customerID',None,None],
----> 61     [None,None,None,'lampID','crystalID'])

~/OneDrive - 3M/Projects/Searchable database/Code/Relational-Database/database_wd_v3.py in create_sqltable(post_meta, name, col_names, col_types, primary_key_flags, link_tos, link_to_table, link_to, many_to_many)
     51                                             link_to_table,
     52                                             link_to,
---> 53                                             many_to_many)))
     54     test.create()

~/OneDrive - 3M/Projects/Searchable database/Code/Relational-Database/database_wd_v3.py in (.0)
     48                     lk_to_table,
     49                     lk_to_col,
---> 50                     mny_to_mny in zip(link_tos,
     51                                             link_to_table,
     52                                             link_to,

TypeError: relationship() got multiple values for argument 'secondary'
由于这是我第一次尝试SQLite和SQLAlchemy,我猜这是我遇到的最小问题。但是,在消除了值传递或甚至直接键入字符串(即secondary='referenceID')之后,我无法纠正这个问题


谢谢你的帮助。

你的参数有问题。当您查看文档时,您将看到第一个参数是目标表,第二个是多对多关系的辅助表。函数签名的重要部分是:

def sqlalchemy.orm.relationship(argument, secondary=None, ...
在代码中,您可以这样称呼它:

relationship(lk_tos, #name of the relationship
                       lk_to_table, #name of the target table
                       secondary=mny_to_mny, #name of the column in the target
                                             # table (many2many relationship)
                       backref=lk_to_col, #name of the column in the target 
                                          # table (many2one relationship)
                       cascade="all,delete")
这里的关键点是传递两个位置参数(
lk_tos
lk_to_table
),根据SQLAlchemy的定义,这两个参数将分别进入
参数和
次要参数。但随后您将传递一个额外的关键字参数,作为
secondary=mny\u to\u mny
。这意味着
secondary
获取值
lk\u to\u table
以及
mny\u to\u mny
。这解释了您看到的错误

我建议将多对多关系从一对多关系中分离出来。这将使您能够更灵活地正确调用函数


不幸的是,我无法在脑海中解开你的代码,给你一个新代码的正确建议。

问题来自于你调用
relationship()
的方式。您确实传递了参数
secondary
两次。因此,错误正是您在回溯中看到的。然而,您的缩写和非语义变量名以及缺少的代码注释使得在不破坏整体逻辑的情况下提供alswer非常困难。这很复杂。如果你把它清理干净,我会再打一次。@exhuma谢谢你看。谢谢你抽出时间。我添加了一些注释来解释我的变量。请让我知道这是否有意义。