Gustavo Sooeiro
Gustavo Sooeiro

Reputation: 327

Django models - how to think

Fellows,

As my system is becoming complex, I need help to think how to implement complex behavior. I will explain:

I have three models: Purchase, PurchaseDetails, and Stock.

The models is as follows:

class Purchase(models.Model):
    def __str__(self):
        return  self.parceiro_pj.razao_social + ' em ' + str(self.data) + ": " + str(self.soma)

    parceiro_pj = models.ForeignKey(ParceiroPJ,blank=True, null=True)
    createdat = models.DateTimeField()
    data = models.DateField(auto_now=True)
    soma = models.DecimalField(max_digits=10, decimal_places=2, default=0.00)

class PurchaseDetails(models.Model):

    def __str__(self):
        return str(self.parceiro_pj_insumo.insumo.nome) + ' - ' + str(self.quantidade) + ' - ' + str(self.createdat)

    purchase = models.ForeignKey(Purchase)
    parceiro_pj_insumo = models.ForeignKey(ParceiroPJInsumo)
    quantidade = models.IntegerField(blank=False, null=False)
    createdat = models.DateField(auto_now=True)

    def save(self, *args, **kwargs):
        super(PurchaseDetail, self).save(*args, **kwargs) # Call the "real" save() method.
        PurchaseDetail.objects.filter(Purchase=self.purchase.id).update(createdat=self.purchase.createdat.date())
        itens = PurchaseDetail.objects.filter(compra=self.purchase.id)
        valor = 0
        for item in itens:
            valor = valor + (item.parceiro_pj_insumo.preco * item.quantidade)

            no_estoque = Estoque.objects.get(insumo=item.parceiro_pj_insumo.insumo.id)
            unidade = Unidade.objects.get(nome=item.parceiro_pj_insumo.insumo.unidade.nome)
            qt = no_estoque.quantidade + item.quantidade
            volume_peso = no_estoque.volume_peso + (item.quantidade * item.parceiro_pj_insumo.insumo.volume_peso)
            Stock.objects.filter(insumo=item.parceiro_pj_insumo.insumo).update(quantidade=qt, unidade=unidade, volume_peso=volume_peso, updatedat=self.purchase.createdat.date())

        Purchase.objects.filter(pk=self.purchase.id).update(soma=valor)
        Purchase.objects.filter(pk=self.purchase.id).update(data=self.purchase.createdat.date())

class Stock(models.Model):

    def __str__(self):
        return str(self.insumo.nome) + '(' + str(self.insumo.marca.nome) +  ')' + ' - ' + str(self.quantidade)

    insumo = models.OneToOneField(Insumo)
    quantidade = models.IntegerField(blank=True, null=True)
    unidade = models.ForeignKey(Unidade, blank=True, null=True)
    volume_peso = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True) 
    updatedat = models.DateField(auto_now=False, blank=True, null=True)

There are related: a) One Purchase has Many PurchaseDetails; b) Every PurchaseDetail has an effect on Stock. For every PurchaseDetail operation (insert, change, delete) the Stock must be updated.

I figure it out how to make the change on Stock every time a PurchaseDetail is inserted. But for the DELETE and UPDATE, the logic seems to be much more complex.

If I edit PurchaseDetails, the way its made, if I already had an item in the database, it will be calculated again when I save the PurchaseDetails (this model is embbeded with the Purchase form at admin), causing error and updating again the Stock.

I dont know how to implement the right way of doing it.

I have to check if its a new item on PurchaseDetail, or if it is a already existent register before update Stock, I dont know how to do it. Also, I dont know hot tom implement the case when I have to delete PurchaseDetails, and decrease items on Stock.

Anyone can help, please?

Upvotes: 1

Views: 166

Answers (1)

Wes Doyle
Wes Doyle

Reputation: 2287

You may consider exploring the functionality provided by Django signals, which will provide you with a nice way to implement this type of behavior. Signals can be sent by built-in model methods like __init__() and save(), and are useful when different areas of your application might want to use information about these types of events.

Some of Django's built-in signals include pre_save, post_save, pre_delete, post_delete, etc; it is also straightforward to define and send your own signals.

Looking at a simplified example of what you already have, lets say you wanted to update a particular Stock every time a related PurchaseDetail was saved, for some reason. You might define a method like:

def update_stock(sender, instance, **kwargs):
    purchase_details_id = instance.id
    # do something here, like update and save a stock

post_save.connect(update_stock, sender=PurchaseDetail)

update_stock is the receiver function which will be called after the save of the PurchaseDetail object.

For further reference: https://docs.djangoproject.com/en/1.10/ref/signals/

Upvotes: 1

Related Questions