Home > database >  Using self.object in CreateView to create objects in other tables
Using self.object in CreateView to create objects in other tables

Time:06-12

When a user makes a new listing using a CreateView, I am trying to use this new object to create a Bid in the Bids table.

class ListingCreateView(CreateView):
    model = Listing 
    fields = ['title', 'description', 'starting_bid', 'url'] 

    def form_valid(self, form):
        form.instance.author = self.request.user
        return super().form_valid(form)
    
    def post(self, request, *args: Any, **kwargs: Any):
        self.object = self.get_object()
        starting_bid = self.request.POST['starting_bid']
        Bids.objects.create(bid_value=starting_bid, bidder=self.request.user, item=self.object)
        return super().post(request, *args, **kwargs)

But it returns the error Generic detail view ListingCreateView must be called with either an object pk or a slug in the URLconf.

The docs say that "When using CreateView you have access to self.object, which is the object being created. If the object hasn’t been created yet, the value will be None."

When using a CreateView, when would self.object contain the object being created? How would I work with the object that has just been created in a CreateView?

CodePudding user response:

You can implement the logic in the .form_valid(…) method [Django-doc], for example:

from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponseRedirect

class ListingCreateView(LoginRequiredMixin, CreateView):
    model = Listing 
    fields = ['title', 'description', 'starting_bid', 'url'] 

    def form_valid(self, form):
        form.instance.author = self.request.user
        self.object = form.save()
        Bids.objects.create(
            bid_value=form.cleaned_data['starting_bid'],
            bidder=self.request.user,
            item=self.object
        )
        return HttpResponseRedirect(self.get_success_url())

Note: normally a Django model is given a singular name, so Bid instead of Bids.


Note: You can limit views to a class-based view to authenticated users with the LoginRequiredMixin mixin [Django-doc].

CodePudding user response:

For such behaviour i strongly recommend using signals.py.

Your apps.py

from django.apps import AppConfig


class YourAppConfig(AppConfig):
    name = 'your_app'

    def ready(self):
        import your_app.signals

signals.py (same folder)

from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Bids, Listing 


@receiver(post_save, sender=Listing)
def create_bids(sender, instance, created, **kwargs):
    if created:
        Bids.objects.create(bidder=instance.author, ...)

created is variable added from Django - True if object has just been created, otherwise False. instance is the object you have just created. Signals are very powerful and you can use them pre- and post save but be aware, that not everything is possible here.

Django Docs

  • Related