Este é um post de José Lopes.
Este post exemplifica como criar um modelo no Django com um atributo composto por outros dois, assegurando a unicidade do mesmo.
Vamos imaginar que temos o seguinte modelo:
class ExampleModel( models.Model ): first_part = models.ForeignKey(OtherModel) second_part = models.CharField(max_length=8) fullname = models.CharField(max_length=19, blank=True, editable=False) def save(self): self.fullname = '%s-%s' % (self.first_part, self.second_part) super(ExampleModel,self).save()
Neste modelo temos o atributo fullname, que não é editável na página de administração, mas é criado sobrepondo o método de gravação (save) seguindo uma determinada forma com base nos atributos first_part e second_part.
Isto segue os exemplos que se encontram facilmente pela web. Propositadamente incluí dois atributos em que um deles é uma ForeignKey só para mostrar que podemos ter qualquer tipo de campo, embora é claro que um ManyToMany não faz sentido para este caso.
Agora quero ainda que este atributo fullname seja único, sendo este o assunto que queria abordar neste post.
Podemos ter a tentação de incluir a unicidade directamente no atributo:
fullname = models.CharField(max_length=19, blank=True, editable=False, unique=True)
Isto põe-nos um problema que é o de múltiplos acessos à nossa aplicação. Como por defeito o atributo é nulo (None), vai-nos causar problemas nos acessos simultâneos respondendo com mensagens de erro em que diz que o valor tem de ser único. Isto claro que não é aceitável.
A solução é bastante simples, recorrendo à classe Meta. O nosso modelo ficaria:
class ExampleModel( models.Model ): first_part = models.ForeignKey(OtherModel) second_part = models.CharField(max_length=8) fullname = models.CharField(max_length=19, blank=True, editable=False) class Meta: unique_together = (('first_part', 'second_part')) def save(self): self.fullname = '%s-%s' % (self.first_part, self.second_part) super(ExampleModel,self).save()
O código em vermelho faz a magia de garantir a unicidade dos atributos first_part e second_part, o que nos serve perfeitamente pois ambos constituem o atributo fullname que queremos que seja único.