遗憾的是,table.alter()
目前不支持外键更新。有一个可以使用的变通方法,但有几个步骤,应该小心执行。最好将此作为功能请求提交到 issue tracker。
使用改变
例如,考虑以下内容:
如果你有 2 个表定义如下:
import datajoint as dj
schema = dj.Schema('rguzman_alter_example')
@schema
class Student(dj.Lookup):
definition = """
student_first_name: varchar(30)
student_last_name: varchar(30)
---
student_location: varchar(30)
"""
contents = [('Joe','Schmoe','Los Angeles,CA'),('Suzie','Queue','Miami,FL')]
@schema
class Assignment (dj.Lookup):
definition = """
assignment_id: int
---
assignment_due_date: date
#-> [nullable] Student # Standard way to define a foreign key on secondary attributes with NULL as default
"""
contents = [dict(assignment_id=100,assignment_due_date='2021-04-21')]
现在假设您希望在二级属性上有一个外键,默认值为 NULL
。您可以将选项传递给辅助属性中的外键(请参阅上面的注释,我们允许它默认为 NULL
)。以这种方式从头开始初始化一个表工作得很好。对于我们想在使用现有数据初始化表后在辅助属性上添加外键的情况,Assignment.alter()
将是实现此目的的最佳方法,只要我们建立一个默认值来填充现有记录和。让我们看看当我们取消对辅助属性的外键的注释,重新定义 Assignment
表类并尝试更改时会发生什么。
---------------------------------------------------------------------------
NotImplementedError Traceback (most recent call last)
<ipython-input-23-09997168281c> in <module>
----> 1 Assignment.alter()
~/.local/lib/python3.7/site-packages/datajoint/table.py in alter(self,prompt,context)
84 del frame
85 old_definition = self.describe(context=context,printout=False)
---> 86 sql,external_stores = alter(self.definition,old_definition,context)
87 if not sql:
88 if prompt:
~/.local/lib/python3.7/site-packages/datajoint/declare.py in alter(definition,context)
367 raise NotImplementedError('table.alter cannot alter the primary key (yet).')
368 if foreign_key_sql != foreign_key_sql_:
--> 369 raise NotImplementedError('table.alter cannot alter foreign keys (yet).')
370 if index_sql != index_sql_:
371 raise NotImplementedError('table.alter cannot alter indexes (yet)')
NotImplementedError: table.alter cannot alter foreign keys (yet).
哦,有一个例外......所以事实证明它尚未针对此用例实现。但是,有一个可以利用的手动解决方法,所以让我详细说明这些步骤,直到获得支持为止。
解决方法
- 不是像上面那样在辅助属性上定义外键,而是这样定义:
@schema
class Assignment (dj.Lookup):
definition = f"""
assignment_id: int
---
assignment_due_date: date
{newline.join(['' + a.name + '=null: ' + a.type for a in Student.heading.attributes.values() if a.in_key])}
"""
contents = [dict(assignment_id=100,assignment_due_date='2021-04-21')]
这会将父表的主要属性“复制”到子表的次要属性中。
- 照常执行变更:
Assignment.alter()
- 直接使用 SQL 查询手动添加外键。像这样:
q = """
ALTER TABLE {table}
ADD FOREIGN KEY ({fk})
REFERENCES {ref} ({pk})
ON UPDATE CASCADE
ON DELETE RESTRICT
""".format(table=Assignment.full_table_name,fk=','.join([f'`{k}`' for k in Student.primary_key]),ref=f'`{Student.table_name}`',pk=','.join([f'`{k}`' for k in Student.primary_key]))
dj.conn().query(q)
- 确保删除在步骤 1 中添加的部分,并用正确的规范替换它,即
-> [nullable] Student
- 重启你的内核
- 要验证是否已正确设置,请检查
Assignment.describe()
。如果一切正常,结果应该是:
assignment_id : int
---
assignment_due_date : date
-> [nullable] Student
此外,任何预先存在的记录现在都应预先填充 NULL
。
本文链接:https://www.f2er.com/647063.html