How can I set two primary key fields for my models in Django How can I set two primary key fields for my models in Django python python

How can I set two primary key fields for my models in Django


I would implement this slightly differently.

I would use a default primary key (auto field), and use the meta class property, 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. 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.

The attribute unique_together in class Meta is only a constraint for your data.


if you should use django on legacy database, you can't modify db_schema

there is a workaround (ugly) method to fix this issue

override the models save or delete function

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