Celery async task on logged in user

I am attempting to run a celery async task from a view, but cannot figure out how to pass the logged in user to the task. Please help…

#views.py

class CallListView(LoginRequiredMixin, FormView, SingleTableView):
    model = Call
    table_class = CallTable
    template_name = 'scraper/call_list.html'
    form_class = CallForm

    def get_success_url(self):
        return reverse("calls")

    def form_valid(self, form):
        scrape_async.delay()
        return super(CallListView, self).form_valid(form)

    def get_queryset(self):
        return Call.objects.filter(user=self.request.user)

#tasks.py

@shared_task
def scrape_async():
    scrape(user)
    return

I have figured out how to run the task on all users but I need it to only run on the logged in user.

Thanks!

You would need to pass the pk of the User to the task as a parameter, and then use it in the task.

I have tried adding request and self to:

def form_valid(self, form):
    scrape_async.delay(self)
    return super(CallListView, self).form_valid(form)

and

@shared_task
def scrape_async(self):
user = get_user_model().objects.get(user=self.request.user)
    scrape(user)
    return

with no luck. I have tried every variation of that I could think of and keep getting errors. Any tips on passing the pk? Thanks!

In the view, self is not the user, self is the instance of the view.

How do you get the user from within the view? (Hint, see your get_queryset function.)

I have tried this:

def form_valid(self, form):
    scrape_async.delay(user=self.request.user)
    return super(CallListView, self).form_valid(form)

but am getting a Object of type User is not JSON serializable error

I have also tried:

def form_valid(self, form):
    user = User.objects.get(user=self.request.user)
    scrape_async.delay(user)
    return super(CallListView, self).form_valid(form)

I am rerunning this now but forget the error I got from that.

Am I close?

You don’t need to pass the entire user object, just the pk of the User object (it’s the id field if you’re not using a custom User object).

But, you already have the reference to the user object as self.request.user - there’s no need to query for it. You should be able to pass self.request.user_id directly as the parameter.

Something like this?

def form_valid(self, form):
    scrape_async.delay(self.request.user_id)
    return super(CallListView, self).form_valid(form)

Yep, that oughta do it.

and my task?

@shared_task
def scrape_async(user_id):
    user = get_user_model().objects.filter(user=user_id)
    scrape(user)
    return
1 Like

Give it a try and see what happens!

2 Likes

With that I am getting a ‘ASGIRequest’ object has no attribute ‘user_id’ error.

I am using Django cookiecutter with its custom user model…

Try using self.request.user.id

I am pushing this to Heroku now to see if it runs:

#views.py

def form_valid(self, form):
    user_id = self.request.user.id
    scrape_async.delay(user_id)
    return super(CallListView, self).form_valid(form)

#tasks.py

@shared_task
def scrape_async(user_id):
    user = get_user_model().objects.get(id=user_id)
    scrape(user)
    return

This with the code below works! Thank you for your time and patience!