Search code examples
djangodatabasepostgresqldjango-modelscomposite-primary-key

How can I use composite primary keys in django?


I want to use composite primary keys in django but I can't find a solution, I tried it in different ways, even trying to make an alter in the table but it won't let me, I want to use it based on this model

class Contiene(models.Model):
    id_boleto = models.OneToOneField("Boleto", primary_key=True, on_delete=models.CASCADE)
    boleto_cdg = models.CharField(default='', max_length=50)  # Asegúrate de que este campo sea opcional
    num_orden = models.ForeignKey("OrdenCompra", on_delete=models.CASCADE)
    cantidad_total = models.IntegerField()

    def generate_random_code(self):
        numbers = ''.join(random.choices(string.digits, k=12))  # Genera 12 números aleatorios
        letters = ''.join(random.choices(string.ascii_uppercase, k=3))  # Genera 3 letras aleatorias
        return numbers + letters

    def save(self, *args, **kwargs):
        # Si no se ha proporcionado un boleto_cdg, entonces genera uno automáticamente
        if not self.boleto_cdg:
            self.boleto_cdg = self.generate_random_code()
        
        # Llamar al método save de la superclase para guardar el objeto
        super(Contiene, self).save(*args, **kwargs)

    def __str__(self):
        return f"{self.id_boleto}{self.num_orden}{self.cantidad_total}{self.boleto_cdg}"`

Where num_orden and id_boleto would become composite pk, please help!!!

I tried different composite key libraries but it gave errors when migrating


Solution

  • I had the same problem in my project and found this solution. By using Meta class, you can have a combination of pks. You can see the answer in the below cell. I hope this helps you.

     class Contiene(models.Model):
        id_boleto = models.OneToOneField("Boleto", primary_key=True, on_delete=models.CASCADE)
        boleto_cdg = models.CharField(default='', max_length=50)  # Asegúrate de que este campo sea opcional
        num_orden = models.ForeignKey("OrdenCompra", on_delete=models.CASCADE)
        cantidad_total = models.IntegerField()
        
         class Meta:
            constraints = [
                models.UniqueConstraint(
                    fields=['id_boleto', 'num_orden'], name='combination_pks'
                )
            ]
    

    You can also read more about the Meta class here. I hope this helps you.