from django.contrib.auth.models import AbstractUser from django.db import models from django.db.models.signals import post_save from django.dispatch import receiver class User(AbstractUser): pass class Profile(models.Model): THEME_CHOICES = ( ('light', 'Light'), ('dark', 'Dark'), ) user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile') is_pro = models.BooleanField(default=False) theme_preference = models.CharField(max_length=10, choices=THEME_CHOICES, default='dark') # Keeping this simple text field for legacy/simple addressing, whilst adding robust Address model below shipping_address = models.TextField(blank=True) stripe_customer_id = models.CharField(max_length=100, blank=True, null=True) def __str__(self): return self.user.username @receiver(post_save, sender=User) def create_user_profile(sender, instance, created, **kwargs): if created: Profile.objects.create(user=instance) @receiver(post_save, sender=User) def save_user_profile(sender, instance, **kwargs): instance.profile.save() class Address(models.Model): ADDRESS_TYPE_CHOICES = ( ('shipping', 'Shipping'), ('billing', 'Billing'), ) user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='addresses') name = models.CharField(max_length=100) street = models.CharField(max_length=200) city = models.CharField(max_length=100) state = models.CharField(max_length=100) zip_code = models.CharField(max_length=20) address_type = models.CharField(max_length=20, choices=ADDRESS_TYPE_CHOICES, default='shipping') is_default = models.BooleanField(default=False) def __str__(self): return f"{self.name} - {self.street}" class PaymentMethod(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='payment_methods') # For now, we'll store mock data. In a real app complexity is higher (PCI compliance etc) brand = models.CharField(max_length=50) # Visa, Mastercard last4 = models.CharField(max_length=4) exp_month = models.PositiveIntegerField() exp_year = models.PositiveIntegerField() is_default = models.BooleanField(default=False) def __str__(self): return f"{self.brand} ending in {self.last4}"