web-dev-qa-db-fra.com

Comment définir deux champs de clé primaire pour mes modèles dans Django

J'ai un modèle comme celui-ci:

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

Je veux que la migration et l'hôte soient ensemble la clé primaire.

44
2 8

Je mettrais cela en œuvre légèrement différemment.

J'utiliserais une clé primaire par défaut (champ automatique) et j'utiliserais la propriété de la méta classe, unique_together

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

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

Il agirait comme une colonne de clé primaire "de substitution".

Si vous voulez vraiment créer une clé primaire multi-colonnes, regardez dans cette application

66
karthikr

Actuellement, Django ne prennent en charge qu'une seule clé primaire de colonne. Si vous ne spécifiez pas primary_key = True pour le champ de votre modèle, Django créera automatiquement une colonne id comme clé primaire.

L'attribut unique_together dans la classe Meta n'est que des contraintes pour vos données.

13
Hùng Ng Vi

si vous devez utiliser Django sur la base de données héritée, vous ne pouvez pas modifier db_schema

il existe une méthode de contournement (laide) pour résoudre ce problème

override les modèles enregistrent ou suppriment la fonction

# 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'),)
2
pulord