如何在 Django 中实现多值属性?
How to implement multivalued attribute in Django?
我有一个包含以下 table 的遗留数据库:
人
person_id (PK) | first_name | last_name
1 | John | Doe
2 | David | Bentley
phone个数
person_id (FK,PK) | phone_number (PK) | area_code (PK)
1 | 758-4551 | 909
1 | 763-3445 | 909
2 | 634-0011 | 637
每个人都可以有零个或多个 phone 数字,这是个人实体的多值属性。
我尝试使用 Django 的 inspectdb 命令生成以下内容 models.py:
class Person(models.Model):
person_id = models.BigIntegerField(primary_key=True)
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
class Meta:
managed = False
db_table = 'person'
class PhoneNumbers(models.Model):
person = models.ForeignKey(Person, models.DO_NOTHING)
phone_number = models.CharField(max_length=15)
area_code = models.CharField(max_length=15)
class Meta:
managed = False
db_table = 'phonenumbers'
unique_together = (('person', 'phone_number', 'area_code'),)
但是,当我尝试保存 PhoneNumbers 的新实例时,Django 返回了以下错误消息:
django.db.utils.ProgrammingError: column phonenumbers.id does not exist
显然 Django 期望 phone 数字的 table 有一个代理键。
由于 phone 号码的 table 不是实体,因此它在我的旧数据库中没有代理键。请注意,phonenumbers 的 table 主键是其所有列的组合。
如何将这些 table 映射到 Django 的模型中,以便它与我的旧数据库一起工作?
在 Django 中,所有模型(为您编写或使用 inspectdb 生成)must kave Primary Key。
如果您想像模型一样使用 table phonenumbers,您将需要这个 table 有一个主键。
在这种情况下,我的建议是您修改遗留 table 以手动添加新的主键并丢弃复合主键。您的遗留 table 有一个复合主键(phone_number+area_code),这不受支持正式在 Django 中。
Django 不支持复合主键,而您的 PhoneNumbers table 有一个跨越三列的主键。这个 ticket has been open for years. There is a third party plugin 提供复合主键支持,但它已经两年没有维护并且与最新版本的 Django 不兼容。
解决方法是添加主键。但在那之前做
./manage.py migrate
这将确保在您的旧数据库中创建了 django 所需的 table。
现在修改您的模型以删除此行
managed = False
这向 django 发出信号,表明对模型的更改将反映在数据库中。然后按如下方式更改您的模型。
class Person(models.Model):
id = models.BigIntegerField(primary_key=True, db_column='person_id')
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
class Meta:
db_table = 'person'
class PhoneNumbers(models.Model):
id = models.BigIntegerField(primary_key=True)
person = models.ForeignKey(Person, models.DO_NOTHING)
phone_number = models.CharField(max_length=15)
area_code = models.CharField(max_length=15)
class Meta:
db_table = 'phonenumbers'
unique_together = (('person', 'phone_number', 'area_code'),)
然后做
./manage.py makemigrations your_app_name
./manage.py migrate
请注意,我已经重命名了 Person 中的主键字段。这只是一个表面上的变化。那是因为约定是将主键字段作为 id。当您处理大量模型时,您可能会忘记该模型的主键的命名方式不同。因此发生了变化。
我有一个包含以下 table 的遗留数据库:
人
person_id (PK) | first_name | last_name
1 | John | Doe
2 | David | Bentley
phone个数
person_id (FK,PK) | phone_number (PK) | area_code (PK)
1 | 758-4551 | 909
1 | 763-3445 | 909
2 | 634-0011 | 637
每个人都可以有零个或多个 phone 数字,这是个人实体的多值属性。
我尝试使用 Django 的 inspectdb 命令生成以下内容 models.py:
class Person(models.Model):
person_id = models.BigIntegerField(primary_key=True)
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
class Meta:
managed = False
db_table = 'person'
class PhoneNumbers(models.Model):
person = models.ForeignKey(Person, models.DO_NOTHING)
phone_number = models.CharField(max_length=15)
area_code = models.CharField(max_length=15)
class Meta:
managed = False
db_table = 'phonenumbers'
unique_together = (('person', 'phone_number', 'area_code'),)
但是,当我尝试保存 PhoneNumbers 的新实例时,Django 返回了以下错误消息:
django.db.utils.ProgrammingError: column phonenumbers.id does not exist
显然 Django 期望 phone 数字的 table 有一个代理键。 由于 phone 号码的 table 不是实体,因此它在我的旧数据库中没有代理键。请注意,phonenumbers 的 table 主键是其所有列的组合。
如何将这些 table 映射到 Django 的模型中,以便它与我的旧数据库一起工作?
在 Django 中,所有模型(为您编写或使用 inspectdb 生成)must kave Primary Key。
如果您想像模型一样使用 table phonenumbers,您将需要这个 table 有一个主键。
在这种情况下,我的建议是您修改遗留 table 以手动添加新的主键并丢弃复合主键。您的遗留 table 有一个复合主键(phone_number+area_code),这不受支持正式在 Django 中。
Django 不支持复合主键,而您的 PhoneNumbers table 有一个跨越三列的主键。这个 ticket has been open for years. There is a third party plugin 提供复合主键支持,但它已经两年没有维护并且与最新版本的 Django 不兼容。
解决方法是添加主键。但在那之前做
./manage.py migrate
这将确保在您的旧数据库中创建了 django 所需的 table。
现在修改您的模型以删除此行
managed = False
这向 django 发出信号,表明对模型的更改将反映在数据库中。然后按如下方式更改您的模型。
class Person(models.Model):
id = models.BigIntegerField(primary_key=True, db_column='person_id')
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
class Meta:
db_table = 'person'
class PhoneNumbers(models.Model):
id = models.BigIntegerField(primary_key=True)
person = models.ForeignKey(Person, models.DO_NOTHING)
phone_number = models.CharField(max_length=15)
area_code = models.CharField(max_length=15)
class Meta:
db_table = 'phonenumbers'
unique_together = (('person', 'phone_number', 'area_code'),)
然后做
./manage.py makemigrations your_app_name
./manage.py migrate
请注意,我已经重命名了 Person 中的主键字段。这只是一个表面上的变化。那是因为约定是将主键字段作为 id。当您处理大量模型时,您可能会忘记该模型的主键的命名方式不同。因此发生了变化。