Composite primary key in django

前端 未结 3 436
孤独总比滥情好
孤独总比滥情好 2020-11-30 03:00

I have a legacy db table which has composite primary key. I don\'t think I will be able to change the structure to include a surrogate key, as there is some code written tha

相关标签:
3条回答
  • 2020-11-30 03:27

    Another option is to set managed=False in the model's Meta, then manually create the table.

    class MyTable(models.Model):
        foo = models.IntegerField(primary_key=True)
        bar = models.IntegerField()
        baz = models.IntegerField()
    
        class Meta:
            managed = False
            db_table = 'myapp_mytable'
    
        def __repr__(self):
            return f'<MyTable: MyTable object ({self.foo}, {self.bar}, {self.baz)>'
    

    In a postgres shell:

    CREATE TABLE myapp_mytable (
        foo INTEGER NOT NULL,
        bar INTEGER NOT NULL,
        baz INTEGER NOT NULL,
        PRIMARY KEY(foo, bar, baz)
    );
    

    It appears to behave correctly:

    >>> MyTable.objects.create(foo=1, bar=1, baz=1)
    <MyTable: MyTable object (1, 1, 1)>
    
    >>> MyTable.objects.create(foo=1, bar=1, baz=2)
    <MyTable: MyTable object (1, 1, 2)>
    
    >>> MyTable.objects.create(foo=1, bar=1, baz=2)
    django.db.utils.IntegrityError: duplicate key value violates unique constraint "myapp_mytable_pkey"
    DETAIL:  Key (foo, bar, baz)=(1, 1, 2) already exists.
    

    Note that this is only tested in Django 3.x, so I'm not sure if it works in older versions.

    0 讨论(0)
  • 2020-11-30 03:32

    The accepted answer is fine. However, it's a little old. unique_together may be deprecated in favor of UniqueConstraint. So, the better way of doing this would be;

    UniqueConstraint(fields = ['key1', 'key2'], name = 'constraint_name')
    
    0 讨论(0)
  • 2020-11-30 03:46

    Try similar below code:

    class MyTable(models.Model):
        class Meta:
            unique_together = (('key1', 'key2'),)
    
        key1 = models.IntegerField(primary_key=True)
        key2 = models.IntegerField()
    

    or if you want only unique mixed fields:

    class MyTable(models.Model):
        class Meta:
            unique_together = (('key1', 'key2'),)
    
        key1 = models.IntegerField()
        key2 = models.IntegerField()
    

    EDIT: I would like to note that there is a problem with this approach if there are 3 columns. Update queries don't work because it tries to update (puts pk fields right after "SET") the fields that are unique together and obviously fails.

    0 讨论(0)
提交回复
热议问题