-
-
Notifications
You must be signed in to change notification settings - Fork 109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Django cookbook #129
Merged
Merged
Django cookbook #129
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
ee92e77
(add/docs)django/drf cookbook
djnnvx d494d02
Merge branch 'Miksus:master' into master
djnnvx 5474085
(mod/docs)adding `import asyncio`
djnnvx afab383
Merge branch 'master' of github.com:bogdzn/rocketry
djnnvx 00602e1
(mod/docs)improving django docs
djnnvx e2b2dc0
(fix/docs)addressing PR comments
djnnvx ec8865e
(fix/docs)typo in django cookbook
djnnvx File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
|
||
Integrate Django (or Django Rest Framework) | ||
=========================================== | ||
|
||
This cookbook will use DRF (Django REST Framework) as an example, but the syntax is exactly | ||
the same for Django. | ||
|
||
First, let's `create a new command <https://docs.djangoproject.com/en/4.1/howto/custom-management-commands>`_ for setting up our jobs (we will call it ``inittasks.py``): | ||
|
||
.. code-block:: python | ||
|
||
# Create Rocketry app | ||
from rocketry import Rocketry | ||
app = Rocketry(config={"task_execution": "async"}) | ||
|
||
# import BaseCommand | ||
from django.core.management.base import BaseCommand | ||
|
||
# Create some tasks | ||
|
||
@app.task('every 5 seconds') | ||
async def do_things(): | ||
... | ||
|
||
class Command(BaseCommand): | ||
help = "Setup the periodic tasks runner" | ||
|
||
def handle(self, *args, **options): | ||
app.run() | ||
|
||
|
||
Next, you can just run in your ``entrypoint`` script (or in your shell) the following command: | ||
|
||
.. code-block:: bash | ||
|
||
... # connect to the database, set PRODUCTION=1, etc... | ||
|
||
# if you deploy on Docker, it's probably better to run this in the background, | ||
# so you can run your HTTP server afterwards | ||
python manage.py inittasks & | ||
|
||
|
||
And you're set ! It's really as simple as that! | ||
|
||
Using the Asynchronous ORM | ||
-------------------------- | ||
|
||
Now, you might have the following error if you use Querysets, or try to use the ORM in your task: | ||
|
||
.. code-block:: bash | ||
|
||
Django: SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async | ||
|
||
.. warning:: | ||
|
||
Some guides might suggest setting the ``DJANGO_ALLOW_ASYNC_UNSAFE`` environment value to ``True``. | ||
This is **not** the recommended way. The UNSAFE keyword is here for a reason. | ||
|
||
For our example, we will use the same file for simplicity, but it's fine to move your tasks to another file | ||
(as long as you don't forget to import them !). | ||
|
||
.. code-block:: python | ||
|
||
# Create Rocketry app | ||
from rocketry import Rocketry | ||
app = Rocketry(config={"task_execution": "async"}) | ||
|
||
# import BaseCommand | ||
from django.core.management.base import BaseCommand | ||
|
||
# this is a synchronous operation that will work in an async context! | ||
def do_things_with_users(name): | ||
for user in User.objects.filter(name=name): | ||
print(f'I did something with {user} !') | ||
|
||
@app.task('every 5 seconds') | ||
async def do_things(): | ||
await sync_to_async(do_things_with_users)(name='John Doe') | ||
... | ||
|
||
class Command(BaseCommand): | ||
help = "Setup the periodic tasks runner" | ||
|
||
def handle(self, *args, **options): | ||
app.run() | ||
|
||
You can even manually run the ``do_things_with_users`` function from a view now, | ||
if that's something you would want. Let's add this view in our ``views.py`` file: | ||
|
||
.. code-block:: python | ||
|
||
# this could be any path where the code you want to run is stored | ||
from api.commands import tasks as tasklist | ||
import asyncio | ||
|
||
... | ||
|
||
class TaskView(APIView): | ||
def get(self, request): | ||
|
||
""" | ||
This function is not ran by our scheduler, and runs in a synchronous context in our example | ||
""" | ||
|
||
name = request.GET.get('name') | ||
if not name : | ||
return Response({ | ||
'error': 'missing a parameter (expected something like ?name=job_name )' | ||
}, | ||
status=HTTP_400_BAD_REQUEST, | ||
) | ||
|
||
try: | ||
|
||
task = getattr(tasklist, name) | ||
|
||
loop = asyncio.new_event_loop() | ||
asyncio.set_event_loop(loop) | ||
|
||
loop.run_until_complete(task()) | ||
|
||
except Exception as err: | ||
|
||
return Response({ | ||
'error': 'task failure', | ||
'logs': f'Failed with: {str(err)}', | ||
}, | ||
status=HTTP_500_INTERNAL_SERVER_ERROR, | ||
) | ||
|
||
return Response({ | ||
'message': 'successfully ran the task', | ||
}, | ||
status=HTTP_200_OK, | ||
) | ||
|
||
|
||
.. note :: | ||
You will only need to use ``sync_to_async`` if you use the asynchronous ORM. The usage is well documented in | ||
`Django's documentation <https://docs.djangoproject.com/en/4.1/topics/async/>`_. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,4 +15,5 @@ do more specific things. | |
robust_applications | ||
controlling_runtime | ||
fastapi | ||
testing | ||
django | ||
testing |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is the
BaseCommand
from? I suppose it should be also imported.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this has been resolved in the latest commit