简体   繁体   English

如何在 Django 中为我的模型设置两个主键字段?

[英]How can I set two primary key fields for my models in Django?

I have a model like this:我有一个这样的模型:

class Hop(models.Model):
    migration = models.ForeignKey('Migration')
    host = models.ForeignKey(User, related_name='host_set')

How can I have the primary key be the combination of migration and host ?我怎样才能让主键成为migrationhost的组合?

Update Django 4.0更新 Django 4.0

Django 4.0 documentation recommends using UniqueConstraint with the constraints option instead of unique_together . Django 4.0 文档建议使用带有约束选项的UniqueConstraint而不是unique_together

Use UniqueConstraint with the constraints option instead.UniqueConstraint与约束选项一起使用。

UniqueConstraint provides more functionality than unique_together . UniqueConstraint提供了比unique_together更多的功能。 unique_together may be deprecated in the future. unique_together 将来可能会被弃用。

class Hop(models.Model):
    migration = models.ForeignKey('Migration')
    host = models.ForeignKey(User, related_name='host_set')

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['migration', 'host'], name='unique_migration_host_combination'
            )
        ]

Original Answer原始答案

I would implement this slightly differently.我会稍微不同地实现这一点。

I would use a default primary key (auto field), and use the meta class property, unique_together我会使用默认主键(自动字段),并使用元类属性unique_together

class Hop(models.Model):
    migration = models.ForeignKey('Migration')
    host = models.ForeignKey(User, related_name='host_set')

    class Meta:
        unique_together = (("migration", "host"),)

It would act as a "surrogate" primary key column.它将充当“代理”主键列。

If you really want to create a multi-column primary key, look into this app如果您真的想创建多列主键,请查看此应用

Currently, Django models only support a single-column primary key.目前,Django 模型只支持单列主键。 If you don't specify primary_key = True for the field in your model, Django will automatically create a column id as a primary key.如果您没有为模型中的字段指定primary_key = True ,Django 将自动创建一个列id作为主键。

The attribute unique_together in class Meta is only a constraint for your data. Meta类中的unique_together属性只是对您的数据的约束。

If you should use Django on a legacy database, you can't modify db_schema .如果你应该在遗留数据库上使用 Django,你不能修改db_schema

There is a workaround (ugly) method to fix this issue:有一种解决方法(丑陋)可以解决此问题:

Override the models save or delete function:覆盖模型保存删除功能:

# Use a raw SQL statement to save or delete the object

class BaseModel(models.Model):

    def get_max_length_unique_key(self):
        max_len_unique_key = []
        for unique_key in self._meta.unique_together:
            if len(unique_key) > len(max_len_unique_key):
                max_len_unique_key = unique_key
        return max_len_unique_key

    def get_db_conn(self):
        db_cnn = DbManage(db_ip, db_port, DATABASES_USER, DATABASES_PASSWORD, self._meta.db_table)
        db_cnn.connect()
        return db_cnn

    def save(self, *args, **kwargs):
        self.delete()
        cnn, databasename = self.get_db_conn()
        update_tables = self._meta.db_table
        key_list = ""
        values_list = ""
        for field in self._meta.fields:
            key_list += "%s," % field.name
            values_list += "\'%s\'," % str(getattr(self, field.name))

        key_list = key_list[:len(key_list) - 1]
        values_list = values_list[:len(values_list) - 1]

        sql = "insert into %s(%s) values(%s)" % (update_tables, key_list, values_list)
        logger.info("insert new record to %s" % databasename)
        cnn.excute_sql(sql)
        cnn.close()

    def delete(self, *args, **kwargs):
        cnn = self.get_db_conn()
        update_tables = self._meta.db_table
        sql = "delete from %s where " % update_tables
        for uk in self.get_max_length_unique_key():
            sql += "%s=\'%s\' and " % (uk, getattr(self, uk))
        sql = sql[:len(sql) - 4]

        logger.info("delete record from %s" % update_tables)
        cnn.excute_sql(sql)
        cnn.close()
        pass

    class Meta:
        abstract = True

class ImageList(BaseModel):

    field1 = models.CharField(primary_key=True, max_length=30)
    field2 = models.CharField(primary_key=True, max_length=30)
    field3 = models.CharField(primary_key=True, max_length=30)
    body = models.CharField(max_length=2000, blank=True, null=True)
    updated_on = models.DateTimeField(blank=True, null=True)

    class Meta:
        managed = True
        db_table = 'image_list'
        unique_together = (('field1', 'field2', 'field3'),)

Since the latest version of Django (4.0.4 at this time) suggests that the unique_together may be deprecated in the future , a more up-to-date solution would be to use the constraints option of the Meta class together with the UniqueConstraint class:由于 Django 的最新版本(此时为 4.0.4)表明 unique_together 将来可能会被弃用,因此更新的解决方案是将 Meta 类的constraints选项与UniqueConstraint类一起使用:

class Hop(models.Model):
    migration = models.ForeignKey('Migration')
    host = models.ForeignKey(User, related_name='host_set')

    class Meta:
        constraints = [
            UniqueConstraint(fields=['migration', 'host'], name='unique_host_migration'),
        ]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM