Python 如何在 Django 中为我的模型设置两个主键字段
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/16800375/
Warning: these are provided under cc-by-sa 4.0 license.  You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can set two primary key fields for my models in Django
提问by 2 8
I have a model like this:
我有一个这样的模型:
class Hop(models.Model):
    migration = models.ForeignKey('Migration')
    host = models.ForeignKey(User, related_name='host_set')
I want to migration and host both together be the primary key.
我想将迁移和托管两者一起作为主键。
采纳答案by karthikr
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
如果你真的想创建一个多列主键,看看这个应用程序
回答by Hùng Ng Vi
Currently, Django models only support a single-column primary key. If you don't specify primary_key = Truefor the field in your model, Django will automatically create a column idas a primary key. 
目前,Django 模型仅支持单列主键。如果您没有primary_key = True为模型中的字段指定,Django 将自动创建一个列id作为主键。
The attribute unique_togetherin class Metais only a constraint for your data.
unique_together类中的属性Meta只是您数据的约束。
回答by pulord
if you should use django on legacy database, you can't modify db_schema
如果您应该在旧数据库上使用 django,则不能修改 db_schema
there is a workaround (ugly) method to fix this issue
有一种解决方法(丑陋)可以解决此问题
overridethe models save or delete function
覆盖模型保存或删除功能
# 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'),)

