【问题标题】:How can I set two primary key fields for my models in Django如何在 Django 中为我的模型设置两个主键字段
【发布时间】:2013-05-23 21:58:40
【问题描述】:

我有一个这样的模型:

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

我希望主键是migrationhost 的组合。

【问题讨论】:

标签: python django django-models model primary-key


【解决方案1】:

我会稍微不同地实现它。

我会使用默认主键(自动字段),并使用元类属性unique_together

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

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

它将充当“代理”主键列。

如果您真的想创建多列主键,请查看this app

【讨论】:

  • 如果我使用unique_together,是否意味着我不必将字段设置为主键?
  • 如果你没有指定AutoField,django 会为你添加一个。所以简而言之,你不会。
  • 这在 2018 年仍然是 Django 2 的最新版本吗?
  • 你会以不同的方式实现这个,但你没有提到你会这样做,因为 Django 不支持主键是多个字段
  • 如果您在遗留数据库上执行上述操作(使用managed=False),您应该使用force_insert=True 调用保存方法,以使它们正常工作。否则 Django 将更新一行而不是添加新记录。
【解决方案2】:

目前,Django 模型仅支持单列主键。如果您没有为模型中的字段指定primary_key = True,Django 将自动创建一个列id 作为主键。

Meta 类中的属性unique_together 只是对您的数据的约束。

【讨论】:

    【解决方案3】:

    如果你应该在遗留数据库上使用 django,你不能修改 db_schema

    有一个解决方法(丑陋的)来解决这个问题

    覆盖模型保存或删除功能

    # use raw sql statement to save or delete 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'),)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-18
      • 1970-01-01
      • 2021-10-24
      • 2014-02-01
      • 2014-12-24
      • 2021-12-15
      • 1970-01-01
      • 2020-10-15
      相关资源
      最近更新 更多