Preserving User Data in Django Orders When Deleting User Account

I have two e-commerce models: User and Order. I need to keep user details in the Order model because transactions have occurred, but I also want to allow users to delete their accounts if they wish. I’m thinking of something like this:

from django.contrib.auth import get_user_model
from django.db import models

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(get_user_model(), on_delete=models.SET_NULL)

    def clean(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.full_clean()
        return super().save(*args, **kwargs)

This approach duplicates data from the User model. Is there a more efficient way to manage this without duplication, or is repeating some fields unavoidable?

hey RyanDragon22, ur approach is ok but there’s a better way. instead of duplicating data, try using a soft delete. just add an ‘is_active’ field to ur User model and set it False when they ‘delete’ their account. this way, u keep the data but it’s not visible. it’s way more efficient and keeps everything intact.

Hey RyanDragon22! That’s an interesting challenge you’ve got there. Have you considered using a historical data model? It’s kinda like keeping a snapshot of user info when they make a purchase.

Here’s a thought: What if you create a UserSnapshot model that stores the user’s details at the time of purchase? You could link this to your Order model instead of duplicating fields. Something like:

class UserSnapshot(models.Model):
    email = models.EmailField()
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    # Add any other fields you need

class Order(models.Model):
    user_snapshot = models.ForeignKey(UserSnapshot, on_delete=models.PROTECT)
    # Other order fields

This way, when a user places an order, you create a UserSnapshot with their current info. If they later delete their account, you still have all the necessary data for the order.

What do you think about this approach? Would it work for your use case? I’m curious to hear your thoughts!

Your approach has merit, but there’s a more elegant solution to consider. Instead of duplicating data, you could implement a historical data model. This involves creating a separate model to store user information at the time of purchase.

Here’s how it might look:

class UserSnapshot(models.Model):
    email = models.EmailField()
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)

class Order(models.Model):
    user_snapshot = models.ForeignKey(UserSnapshot, on_delete=models.PROTECT)
    # Other order fields

# In your view or service layer
def create_order(user, ...):
    snapshot = UserSnapshot.objects.create(
        email=user.email,
        first_name=user.first_name,
        last_name=user.last_name
    )
    order = Order.objects.create(user_snapshot=snapshot, ...)

This approach preserves user data for each order without duplicating fields in the Order model. It also allows for easy account deletion without losing order history. You might want to consider adding a timestamp to the UserSnapshot model for auditing purposes.