Narration / Transcript

Consuming paginated API using periodic Celery tasks in Django

This is what the narrator says, not what the page shows: equations are read as sentences, code blocks are described, and citations are spoken as citations.

52 blocks · 1,141 spoken words · narrated Jul 26, 2026

  1. 0:00

    Introduction

  2. 0:02

    API (Application Programming Interface) consumption is the new normal in contemporary times as many software products have shifted focus on decoupling Backend and Frontend codebases. Backend Engineers are tasked with writing consumable APIs that their Frontend counterparts consume. In some cases, even Backend Engineers utilize some other API services to accomplish their tasks.

  3. 0:28

    Some services provide an enormously large dataset so making them accessible at a single API call might not be great. Pagination then comes to the rescue. Many APIs are now paginated to make available a fraction of the data. To access other fractions, you need some extra tasks.

  4. 0:48

    This article demonstrates how to set up Celery background tasks to consume paginated APIs periodically. We'll explore iterative and recursive approaches for APIs paginated using page parameters and those using next URLs. The fetched data will be stored in a Django model, overwriting previous data. Note that persisting historical data is outside the scope of this article but will be addressed in a future post on building a data warehouse.

  5. 1:16

    Prerequisite

  6. 1:18

    Basic familiarity with Django is assumed. Refer to the Django tutorial for an introduction.

  7. 1:25

    Source code Sirneij/django_excel

  8. 1:28

    Exporting Django model data as excel file (.xlsx) using openpyxl library and Google Spreadsheet API python html5 bash heroku

  9. 1:40

    Implementation

  10. 1:42

    Step 1: Setup Django project and app with celery

  11. 1:46

    Create a Django project named django excel within a virtual environment. Ensure that django and celery are installed in your environment. The shell code below is 1 line.

  12. 1:59

    Create an app named core: The shell code below is 1 line.

  13. 2:03

    Register your application in settings dot py. The Python code below is 14 lines, from django excel slash settings dot py.

  14. 2:13

    It is time to set up our application to utilize Celery. To do this, create a file aptly named celery dot py in your project's directory and paste the following snippet: The Python code below defines debug task, 22 lines, from django excel slash celery dot py.

  15. 2:31

    That was directly lifted from Celery Django documentation. Ensure you modify lines 6 and 8 to reflect your project's name. The namespace in line 14 enables you to prefix all celery-related configurations in your settings dot py file with CELERY such as CELERY BROKER URL. Note: Capitalization of Celery-Related Configurations

  16. 2:55

    Because you are literarily providing constants, the celery-related configurations in your settings dot py file are capitalized. For instance, one of the configurations is beat schedule which in Django, becomes CELERY BEAT SCHEDULE.

  17. 3:11

    Next, open open your project's init dot py and append the following: The Python code below is 5 lines, from django excel slash init dot py.

  18. 3:22

    To conclude celery-related configurations, let's set the following in settings dot py: The Python code below is 6 lines.

  19. 3:31

    We are using redis as our broker. You can opt for RabbitMQ which is supported out-of-box by celery.

  20. 3:38

    In the settings above, I am linking CELERY BROKER URL to an environment variable named REDIS URL. It normally should look like redis: slash slash 127.0.0.1:6379 on a Linux system. That means I could have set my CELERY BROKER URL and CELERY RESULT BACKEND as: The Python code below is 10 lines.

  21. 4:02

    Note that CELERY RESULT BACKEND is optional as well as CELERY ACCEPT CONTENT, CELERY TASK SERIALIZER, and CELERY RESULT SERIALIZER. However, not setting the last three might result in some runtime errors mostly when dealing with databases in asynchronous email broadcasting with celery.

  22. 4:22

    The stage is now set, let's set up our database. We will be consuming CoinGecko's API and will be saving some data.

  23. 4:31

    Step 2: Define Full Coin model

  24. 4:34

    Our model will look like this: The Python code below defines Full Coin and str, 31 lines, from core slash models dot py.

  25. 4:43

    These are all the fields taken directly from CoinGecko's public API for coin markets: The JSON code below is 30 lines. Note: Commission from referral

  26. 4:55

    If you use Coingecko's API, when you use my code, CGSIRNEIJ, I get some commissions. That can be a good way to support me.

  27. 5:04

    null equals True makes a column nullable in SQL: The SQL code below is 4 lines.

  28. 5:10

    null equals False or leaving it unset makes the column non-nullable: The SQL code below is 4 lines.

  29. 5:18

    blank equals True allows the field to be optional in forms and the admin page.

  30. 5:24

    Talking about the admin site, let's register the model: The Python code below defines Full Coin Admin, 32 lines, from core slash admin dot py.

  31. 5:35

    With this, you can migrate your database: The shell code below is 2 lines, from Terminal.

  32. 5:41

    Optionally, you can create a superuser: The shell code below is 1 line, from Terminal.

  33. 5:47

    Follow the prompts.

  34. 5:49

    Step 3: Create and Register Periodic Tasks

  35. 5:53

    Here is the juicy part: The Python code below defines build api url, fetch coins iteratively and get full coin data iteratively for page, 80 lines, from core slash tasks dot py.

  36. 6:07

    The build api url helps continuously build CoinGecko API url based on the supplied page number. The BASE API URL is: The Python code below is 2 lines, from django excel slash settings dot py.

  37. 6:24

    fetch coins iteratively is the core of the program. It starts with the first page and does an "infinite" loop which breaks only when there's no data returned by the API using the iterative strategy.

  38. 6:37

    Its recursive alternative is: The Python code below defines fetch coins recursively, 31 lines.

  39. 6:45

    Then there is the get full coin data iteratively for page which is decorated by shared task (for task autodiscovery). We supplied some parameters:

  40. 6:55

    bind equals True to access task instance via self

  41. 6:59

    autoretry for equals Exception, to auto-retry on exceptions

  42. 7:04

    retry backoff equals True for exponential backoff

  43. 7:08

    max retries equals 5 to limit retries to 5

  44. 7:13

    For this task to be periodic, we must add it to the CELERY BEAT SCHEDULE in settings dot py: The Python code below is 8 lines, from django excel slash settings dot py.

  45. 7:25

    It schedules this task to run every 3 minutes (star slash 3) using crontab.

  46. 7:31

    These implementations were with performance in mind. However, there is still room for improvement.

  47. 7:37

    Step 4: Bonus

  48. 7:39

    There are APIs whose paginations are not page -based but use the next (default DRF pagination strategy). For these systems, the last bits of data have empty next. That's the breaking point: The Python code below defines get api data, 8 lines.

  49. 7:57

    That's it! I hope you enjoyed it.

  50. 8:00

    Outro

  51. 8:02

    Enjoyed this article? I'm a Software Engineer, Technical Writer, and Technical Support Engineer actively seeking new opportunities, particularly in areas related to web security, finance, healthcare, and education. If you think my expertise aligns with your team's needs, let's chat! You can find me on LinkedIn and X. I am also an email away.

  52. 8:24

    If you found this article valuable, consider sharing it with your network to help spread the knowledge!