SpellTheif
SpellTheif

Reputation: 715

Django - automatically create a model instance when another model instance is created

I have an overrided User model and a Cart model. I expect that a Cart model instance is created automatically once a User model instance is created. I am trying to pass the newly registered user into the get_queryset method, but no idea how to do it. Are there any other better ways of doing this? It's because I may need to do the same thing for other models unlike the User model which has a form that can pass values to the get_queryset method.

account/models.py:

class Cart(models.Model):

    user = models.OneToOneField(User, on_delete=models.CASCADE, null=True)

    def __str__(self):
        return self.user.email + '_cart'

account/views.py:

class RegisterView(generic.CreateView):
    template_name = 'account/register.html'
    form_class = RegisterForm
    success_url = reverse_lazy('book:home')

    def get_queryset(self):
        sign_up = self.request.POST.get('register')
        if sign_up:
            c = Cart.objects.create(user=???)
            c.save()

account/templates/account/register.html:

<form name="register" method="post">{% csrf_token %}
    {{ form.as_p }}
    <input type="submit" value="Sign Up">
</form>

Upvotes: 11

Views: 11142

Answers (4)

Rob
Rob

Reputation: 1909

I believe the modern ways (as per the docs) are to do this during a create() class method or to write a custom manager.

https://docs.djangoproject.com/en/3.1/ref/models/instances/

Upvotes: 0

jcirni
jcirni

Reputation: 57

override save method, signals are harder to read/track through multiple files and are synchronous.

https://lincolnloop.com/blog/django-anti-patterns-signals/

class Pizza(models.Model):
    has_pepperoni = models.BooleanField(default=False)

    def save(self, *args, **kwargs):
        created = self.pk is None
        super(Pizza, self).save(*args, **kwargs)
        if created and self.has_pepperoni:
            ToppingSales.objects.filter(name='pepperoni').update(
                units_sold=F('units_sold') + 1)           


class ToppingSales(models.Model):
    name = models.CharField(max_length=100, unique=True)
    units_sold = models.PositiveIntegerField(default=0)

Upvotes: 2

JPG
JPG

Reputation: 88499

Method-1: Use Django's post_save signal (as @AKX said)

from django.contrib.auth import get_user_model


@receiver(post_save, sender=get_user_model())
def create_user_cart(sender, instance, created, **kwargs):
    if created:
        Cart.objects.create(user=instance)


Method-2: Override the save() method of your User model or extended Usermodel

class MyUserModel(....):
    # your code
    def save(self,*args,**kwargs):
        created = not self.pk
        super().save(*args,**kwargs)
        if created:
            Cart.objects.create(user=self)

Upvotes: 23

AKX
AKX

Reputation: 168967

Use a Django post_save signal hooked up to the User model.

See the signals tutorial for more information.

Upvotes: 8

Related Questions