Django: Preserve customer data after account deletion in e-commerce app

I’m working on an e-commerce app using Django. I’ve got two models: Shopper and Purchase. I want to keep the Shopper’s info when they make a Purchase, but also let them delete their account if they want to.

Right now, my Purchase model looks like this:

class Purchase(models.Model):
    buyer_email = models.EmailField()
    buyer_first_name = models.CharField(max_length=50)
    buyer_last_name = models.CharField(max_length=50)
    buyer = models.ForeignKey(Shopper, on_delete=models.SET_NULL)

    def prepare_data(self):
        if not self.buyer_first_name:
            self.buyer_first_name = self.buyer.first_name
        if not self.buyer_last_name:
            self.buyer_last_name = self.buyer.last_name
        if not self.buyer_email:
            self.buyer_email = self.buyer.email

    def save(self, *args, **kwargs):
        self.prepare_data()
        super().save(*args, **kwargs)

This feels like I’m repeating myself a lot. Is there a better way to do this without copying fields from the Shopper model? Or do I just have to deal with the duplication? Any ideas would be great!

hey sophie, maybe try using a separate model for storing historical data? when a shopper deletes their account, copy their info to this model and link it to the purchase. This way u keep the purchase data without duplicating fields in the Purchase model. it’s a bit more work upfront but could save you headaches later on!

I’ve faced a similar issue in my Django projects. Instead of duplicating fields, consider using a soft delete approach for your Shopper model. Add an ‘is_active’ boolean field to Shopper and override the delete method to set it to False instead of actually deleting the record. This way, you maintain the integrity of your Purchase data while allowing users to ‘delete’ their accounts.

For the Purchase model, you can simplify it by relying on the ForeignKey relationship:

class Purchase(models.Model):
    buyer = models.ForeignKey(Shopper, on_delete=models.SET_NULL, null=True)

    @property
    def buyer_email(self):
        return self.buyer.email if self.buyer else None

    @property
    def buyer_full_name(self):
        return f'{self.buyer.first_name} {self.buyer.last_name}' if self.buyer else None

This approach eliminates field duplication and simplifies your code while preserving all necessary data.

Hey Sophie26! Your question’s got me thinking about some cool ways to handle this. Have you considered using a custom manager for your Shopper model? It could be a neat solution!

Here’s an idea: create a custom manager that handles ‘deleting’ a shopper by anonymizing their data instead of actually removing it. Something like this:

class ShopperManager(models.Manager):
    def delete(self, *args, **kwargs):
        self.update(
            first_name='Deleted',
            last_name='User',
            email=f'deleted_{uuid.uuid4()}@example.com'
        )

class Shopper(models.Model):
    # Your existing fields here
    objects = ShopperManager()

This way, when a shopper ‘deletes’ their account, you’re just updating their info to anonymous data. Your Purchase model can stay as is, keeping the link to the Shopper without duplicating fields.

What do you think about this approach? It might solve your problem without adding too much complexity. Have you tried anything similar before?