Home > OS >  Async run script from "python manage.py shell"?
Async run script from "python manage.py shell"?

Time:10-05

As far as I can tell, running a script from python manage.py shell like python manage.py shell < import.py is done synchronously:

# models.py
class PersonManager(models.Manager):
    def generate_num_children(self, persons):
        for person in persons:
            person.generate_num_children()


class ParentManager(models.Manager):
    def generate_num_grandchildren(self, parents):
        for parent in parents:
            parent.generate_num_grandchildren()


class Person(models.Model):
    objects = PersonManager()
    num_children = models.IntegerField(default=0)
    parent = models.ForeignKey(related_name="children")

    def generate_num_children(self):
        self.num_children = 1
        self.save()


class Parent(models.Model):
    objects = ParentManager()
    num_grandchildren = models.IntegerField()

    def generate_num_grandchildren(self):
        num = 0       
        for child in self.children.all():
            num  = child.num_children
        self.num_grandchildren = num
        self.save()
    
# import.py
parent = Parent.objects.create(id=1)

person1 = Person.objects.create(id=2, parent=parent)
person2 = Person.objects.create(id=3, parent=parent)
person3 = Person.objects.create(id=4, parent=parent)

persons = Person.objects.all()
Person.objects.generate_num_children(persons)

parent.generate_num_grandchildren()

# python manage.py shell
Parent.objects.get(id=1).num_grandchildren # Returns 0

When I enter each line individually in python manage.py shell or in a test file however, the code runs asynchronously and gives me the correct result:

parent = Parent.objects.create(id=1)
person1 = Person.objects.create(id=2, parent=parent)
person2 = Person.objects.create(id=3, parent=parent)
person3 = Person.objects.create(id=4, parent=parent)

persons = Person.objects.all()
Person.objects.generate_num_children(persons)

parent.generate_num_grandchildren()

Parent.objects.get(id=1).num_grandchildren # Returns 3

So how can I make my import.py file async?

# import.py
# Run first
parent = Parent.objects.create(id=1)

person1 = Person.objects.create(id=2, parent=parent)
person2 = Person.objects.create(id=3, parent=parent)
person3 = Person.objects.create(id=4, parent=parent)

persons = Person.objects.all()
Person.objects.generate_num_children(persons)

# Run only when previous section is complete
parent.generate_num_grandchildren()

CodePudding user response:

A Django shell script is normal Python, so you can use any of the build-in features for running asynchronous code in Python:

  • Threads
  • Processes
  • Asyncio

Or you can use a task queue system like Celery for it.

If you are not already using something like Celery on your site, I would suggest looking into threads.

  • Related