├── .github └── workflows │ └── django.yml ├── .gitignore ├── LICENSE ├── README.md ├── dj_celery_progress_sample ├── __init__.py ├── asgi.py ├── celery.py ├── celeryconfig.py ├── core │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── management │ │ └── commands │ │ │ └── generate_user.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── tests.py │ └── views.py ├── forms.py ├── settings.py ├── tasks │ ├── __init__.py │ ├── base.py │ ├── export_user_task.py │ └── import_user_task.py ├── urls.py ├── utils.py ├── views.py └── wsgi.py ├── manage.py ├── requirements.txt ├── runcelery.sh ├── static └── docs │ └── users-template.xlsx └── templates ├── index.html └── navbar.html /.github/workflows/django.yml: -------------------------------------------------------------------------------- 1 | name: Django CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | strategy: 14 | max-parallel: 4 15 | matrix: 16 | python-version: [3.6, 3.7, 3.8] 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | - name: Set up Python ${{ matrix.python-version }} 21 | uses: actions/setup-python@v2 22 | with: 23 | python-version: ${{ matrix.python-version }} 24 | - name: Install Dependencies 25 | run: | 26 | python -m pip install --upgrade pip 27 | pip install -r requirements.txt 28 | - name: Run Tests 29 | run: | 30 | python manage.py test 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | media/ 2 | media/* 3 | static/resources/ 4 | static/resources/* 5 | static/root/ 6 | .vscode/ 7 | .vscode/* 8 | .scannerwork/ 9 | .scannerwork/* 10 | .sonar/ 11 | node_modules/ 12 | node_modules/* 13 | 14 | *.ipynb 15 | .env 16 | .env.db 17 | .docker-env 18 | .dockerignore 19 | sonar-project.properties 20 | Dockerfile 21 | docker-compose.debug.yml 22 | docker-compose.yml 23 | 24 | Pipfile 25 | Pipfile.lock 26 | 27 | crom_platform/local_settings.py 28 | local_runtest.sh 29 | 30 | # Byte-compiled / optimized / DLL files 31 | __pycache__/ 32 | *.py[cod] 33 | *$py.class 34 | 35 | # C extensions 36 | *.so 37 | 38 | # Distribution / packaging 39 | .Python 40 | build/ 41 | develop-eggs/ 42 | dist/ 43 | downloads/ 44 | eggs/ 45 | .eggs/ 46 | lib/ 47 | lib64/ 48 | parts/ 49 | sdist/ 50 | var/ 51 | wheels/ 52 | pip-wheel-metadata/ 53 | share/python-wheels/ 54 | *.egg-info/ 55 | .installed.cfg 56 | *.egg 57 | MANIFEST 58 | 59 | # PyInstaller 60 | # Usually these files are written by a python script from a template 61 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 62 | *.manifest 63 | *.spec 64 | 65 | # Installer logs 66 | pip-log.txt 67 | pip-delete-this-directory.txt 68 | 69 | # Unit test / coverage reports 70 | htmlcov/ 71 | .tox/ 72 | .nox/ 73 | .coverage 74 | .coverage.* 75 | .cache 76 | nosetests.xml 77 | coverage.xml 78 | *.cover 79 | .hypothesis/ 80 | .pytest_cache/ 81 | 82 | # Translations 83 | *.mo 84 | *.pot 85 | 86 | # Django stuff: 87 | *.log 88 | local_settings.py 89 | db.sqlite3 90 | db.sqlite3-journal 91 | 92 | # Flask stuff: 93 | instance/ 94 | .webassets-cache 95 | 96 | # Scrapy stuff: 97 | .scrapy 98 | 99 | # Sphinx documentation 100 | docs/_build/ 101 | 102 | # PyBuilder 103 | target/ 104 | 105 | # Jupyter Notebook 106 | .ipynb_checkpoints 107 | 108 | # IPython 109 | profile_default/ 110 | ipython_config.py 111 | 112 | # pyenv 113 | .python-version 114 | 115 | # pipenv 116 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 117 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 118 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 119 | # install all needed dependencies. 120 | #Pipfile.lock 121 | 122 | # celery beat schedule file 123 | celerybeat-schedule 124 | 125 | # SageMath parsed files 126 | *.sage.py 127 | 128 | # Environments 129 | .env 130 | .venv 131 | env/ 132 | venv/ 133 | ENV/ 134 | env.bak/ 135 | venv.bak/ 136 | 137 | # Spyder project settings 138 | .spyderproject 139 | .spyproject 140 | 141 | # Rope project settings 142 | .ropeproject 143 | 144 | # mkdocs documentation 145 | /site 146 | 147 | # mypy 148 | .mypy_cache/ 149 | .dmypy.json 150 | dmypy.json 151 | 152 | # Pyre type checker 153 | .pyre/ 154 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Eby Sofyan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Django + Celery + Progress Bar 2 | 3 | 👻 A repository that provides sample export and import data into excel file using Django + Celery + Pandas with a Progress Bar ❤️ 4 | 5 | ## Key Features 6 | - [x] Built with Django + Celery + Pandas + ❤️ 7 | - [x] Export Into Excel With Progress Bar 8 | - [x] Import From Excel With Progress Bar 9 | -------------------------------------------------------------------------------- /dj_celery_progress_sample/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, unicode_literals 2 | from .celery import app as celery_app 3 | 4 | __all__ = ('celery_app', ) 5 | -------------------------------------------------------------------------------- /dj_celery_progress_sample/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for dj_celery_progress_sample project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.1/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dj_celery_progress_sample.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /dj_celery_progress_sample/celery.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, unicode_literals 2 | 3 | import os 4 | 5 | from django.conf import settings 6 | 7 | from celery import Celery 8 | from . import celeryconfig 9 | 10 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dj_celery_progress_sample.settings') 11 | 12 | app = Celery('django-celery-progress-sample', 13 | broker=celeryconfig.broker_url, 14 | backend=celeryconfig.result_backend) 15 | app.config_from_object("dj_celery_progress_sample.celeryconfig") 16 | app.autodiscover_tasks(settings.INSTALLED_APPS) 17 | 18 | 19 | @app.task(bind=True) 20 | def debug_task(self): 21 | print('Request: {0!r}'.format(self.request)) 22 | -------------------------------------------------------------------------------- /dj_celery_progress_sample/celeryconfig.py: -------------------------------------------------------------------------------- 1 | import os 2 | import tempfile 3 | 4 | broker_url = "redis://localhost:6379/0" 5 | result_backend = "redis://localhost:6379/0" 6 | accept_content = ["pickle", "json", "msgpack", "yaml"] 7 | task_ignore_result = False 8 | -------------------------------------------------------------------------------- /dj_celery_progress_sample/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebysofyan/django-celery-progress-sample/311289c01a6d603daafd804d30699b0019e47409/dj_celery_progress_sample/core/__init__.py -------------------------------------------------------------------------------- /dj_celery_progress_sample/core/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /dj_celery_progress_sample/core/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class CoreConfig(AppConfig): 5 | name = 'core' 6 | -------------------------------------------------------------------------------- /dj_celery_progress_sample/core/management/commands/generate_user.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.models import User 2 | from django.core.management import BaseCommand 3 | 4 | 5 | class Command(BaseCommand): 6 | help = "Generating fake user by running python manage.py generate_user" 7 | 8 | def handle(self, *args, **kwargs): 9 | for i in range(0, 500): 10 | User.objects.create_user( 11 | username="username_%s" % i, 12 | password="password_%s_123" % i, 13 | email="username_%s@email.com" % i, 14 | first_name="first_name_%s" % i, 15 | last_name="last_name_%s" % i, 16 | is_superuser=bool(i % 2 == 0), 17 | is_staff=bool(i % 2 != 0) 18 | ) 19 | print("Insrting item %s" % i) 20 | -------------------------------------------------------------------------------- /dj_celery_progress_sample/core/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebysofyan/django-celery-progress-sample/311289c01a6d603daafd804d30699b0019e47409/dj_celery_progress_sample/core/migrations/__init__.py -------------------------------------------------------------------------------- /dj_celery_progress_sample/core/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /dj_celery_progress_sample/core/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /dj_celery_progress_sample/core/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /dj_celery_progress_sample/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | class ImportFileForm(forms.Form): 4 | document_file = forms.FileField() -------------------------------------------------------------------------------- /dj_celery_progress_sample/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for dj_celery_progress_sample project. 3 | 4 | Generated by 'django-admin startproject' using Django 3.1.2. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.1/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/3.1/ref/settings/ 11 | """ 12 | 13 | import os 14 | import sys 15 | from pathlib import Path 16 | 17 | # Build paths inside the project like this: BASE_DIR / 'subdir'. 18 | BASE_DIR = Path(__file__).resolve().parent.parent 19 | 20 | 21 | # Quick-start development settings - unsuitable for production 22 | # See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/ 23 | 24 | # SECURITY WARNING: keep the secret key used in production secret! 25 | SECRET_KEY = '$v2d2u($$$mp=$82b)lgt%-ls!qxa80l0pp-qn)e9%33ue5+__' 26 | 27 | # SECURITY WARNING: don't run with debug turned on in production! 28 | DEBUG = True 29 | 30 | ALLOWED_HOSTS = [] 31 | 32 | DIRNAME = os.path.dirname(__file__) 33 | sys.path.append(os.path.join(DIRNAME, '')) 34 | 35 | # Application definition 36 | 37 | INSTALLED_APPS = [ 38 | 'django.contrib.admin', 39 | 'django.contrib.auth', 40 | 'django.contrib.contenttypes', 41 | 'django.contrib.sessions', 42 | 'django.contrib.messages', 43 | 'django.contrib.staticfiles', 44 | "celery_progress", 45 | "django_extensions", 46 | "corsheaders", 47 | "core", 48 | ] 49 | 50 | MIDDLEWARE = [ 51 | 'django.middleware.security.SecurityMiddleware', 52 | 'django.contrib.sessions.middleware.SessionMiddleware', 53 | 'corsheaders.middleware.CorsMiddleware', 54 | 'django.middleware.common.CommonMiddleware', 55 | 'django.middleware.csrf.CsrfViewMiddleware', 56 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 57 | 'django.contrib.messages.middleware.MessageMiddleware', 58 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 59 | ] 60 | 61 | CORS_ALLOW_ALL_ORIGINS = True 62 | 63 | ROOT_URLCONF = 'dj_celery_progress_sample.urls' 64 | 65 | TEMPLATES = [ 66 | { 67 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 68 | 'DIRS': [ 69 | os.path.join(BASE_DIR, "templates") 70 | ], 71 | 'APP_DIRS': True, 72 | 'OPTIONS': { 73 | 'context_processors': [ 74 | 'django.template.context_processors.debug', 75 | 'django.template.context_processors.request', 76 | 'django.contrib.auth.context_processors.auth', 77 | 'django.contrib.messages.context_processors.messages', 78 | ], 79 | }, 80 | }, 81 | ] 82 | 83 | WSGI_APPLICATION = 'dj_celery_progress_sample.wsgi.application' 84 | 85 | 86 | # Database 87 | # https://docs.djangoproject.com/en/3.1/ref/settings/#databases 88 | 89 | DATABASES = { 90 | 'default': { 91 | 'ENGINE': 'django.db.backends.sqlite3', 92 | 'NAME': BASE_DIR / 'db.sqlite3', 93 | } 94 | } 95 | 96 | 97 | # Password validation 98 | # https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators 99 | 100 | AUTH_PASSWORD_VALIDATORS = [ 101 | { 102 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 103 | }, 104 | { 105 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 106 | }, 107 | { 108 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 109 | }, 110 | { 111 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 112 | }, 113 | ] 114 | 115 | 116 | # Internationalization 117 | # https://docs.djangoproject.com/en/3.1/topics/i18n/ 118 | 119 | LANGUAGE_CODE = 'en-us' 120 | 121 | TIME_ZONE = 'UTC' 122 | 123 | USE_I18N = True 124 | 125 | USE_L10N = True 126 | 127 | USE_TZ = True 128 | 129 | 130 | # Static files (CSS, JavaScript, Images) 131 | # https://docs.djangoproject.com/en/3.1/howto/static-files/ 132 | 133 | STATIC_URL = '/static/' 134 | STATIC_ROOT = os.path.join(BASE_DIR, 'static/root/') 135 | 136 | MEDIA_URL = "/media/" 137 | MEDIA_ROOT = os.path.join(BASE_DIR, "media") 138 | -------------------------------------------------------------------------------- /dj_celery_progress_sample/tasks/__init__.py: -------------------------------------------------------------------------------- 1 | from .export_user_task import export_user_task 2 | from .import_user_task import import_user_task 3 | 4 | __all__ = (export_user_task, import_user_task) 5 | -------------------------------------------------------------------------------- /dj_celery_progress_sample/tasks/base.py: -------------------------------------------------------------------------------- 1 | from dj_celery_progress_sample import celery_app 2 | 3 | 4 | class BaseTask(celery_app.Task): 5 | ignore_result = False 6 | 7 | def __call__(self, *args, **kwargs): 8 | print("Starting %s" % self.name) 9 | return self.run(*args, **kwargs) 10 | 11 | def after_return(self, status, retval, task_id, args, kwargs, einfo): 12 | # exit point of the task whatever is the state 13 | print("End of %s" % self.name) 14 | -------------------------------------------------------------------------------- /dj_celery_progress_sample/tasks/export_user_task.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | import tempfile 4 | from os import name 5 | from re import template 6 | 7 | from celery_progress.backend import ProgressRecorder 8 | from dj_celery_progress_sample import celery_app 9 | from django.conf import settings 10 | from django.contrib.auth.models import User 11 | from django.http import Http404, HttpResponse 12 | from django.utils import timezone 13 | from openpyxl import Workbook, load_workbook 14 | 15 | from .base import BaseTask 16 | 17 | 18 | class ExportUserIntoExcelTask(BaseTask): 19 | name = "ExportUserIntoExcelTask" 20 | 21 | def __init__(self, *args, **kwargs) -> None: 22 | super().__init__(*args, **kwargs) 23 | self.queryset = User.objects.all() 24 | 25 | def copy_and_get_copied_path(self): 26 | template_path = os.path.join(settings.BASE_DIR, "static/docs/users-template.xlsx") 27 | destination_path = "%s/%s-exported-users.xlsx" % (tempfile.gettempdir(), int(timezone.now().timestamp())) 28 | shutil.copy(template_path, destination_path) 29 | return destination_path 30 | 31 | def create_row(self, instance: User): 32 | return ( 33 | instance.username, 34 | instance.first_name, 35 | instance.last_name, 36 | instance.is_active, 37 | instance.is_staff, 38 | instance.is_superuser 39 | ) 40 | 41 | def create_workbook(self, workbook: Workbook): 42 | progress_recorder = ProgressRecorder(self) 43 | total_record = self.queryset.count() 44 | sheet = workbook.active 45 | for index, instance in enumerate(self.queryset): 46 | print("Appending %s into excel" % instance.username) 47 | sheet.append(self.create_row(instance)) 48 | progress_recorder.set_progress(index + 1, total=total_record, description="Inserting record into row") 49 | return workbook 50 | 51 | def run(self, *args, **kwargs): 52 | destination_path = self.copy_and_get_copied_path() 53 | workbook = load_workbook(destination_path) 54 | workbook = self.create_workbook(workbook) 55 | workbook.save(filename=destination_path) 56 | return { 57 | "detail": "Successfully export user", 58 | "data": { 59 | "outfile": destination_path 60 | } 61 | } 62 | 63 | 64 | @celery_app.task(bind=True, base=ExportUserIntoExcelTask) 65 | def export_user_task(self, *args, **kwargs): 66 | return super(type(self), self).run(*args, **kwargs) 67 | -------------------------------------------------------------------------------- /dj_celery_progress_sample/tasks/import_user_task.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | import tempfile 4 | from os import name 5 | from re import template 6 | 7 | from celery_progress.backend import ProgressRecorder 8 | from dj_celery_progress_sample import celery_app 9 | from django.conf import settings 10 | from django.contrib.auth.models import User 11 | from django.http import Http404, HttpResponse 12 | from django.utils import timezone 13 | from openpyxl import Workbook, load_workbook 14 | 15 | from ..utils import DataframeUtil 16 | from .base import BaseTask 17 | 18 | 19 | class ImportUserFromExcelTask(BaseTask): 20 | name = "ImportUserFromExcelTask" 21 | 22 | def insert_into_row(self, row: dict) -> User: 23 | u, _ = User.objects.get_or_create(username=row.get("username")) 24 | u.set_password(row.get("password")) 25 | u.first_name = row.get("first name") 26 | u.last_name = row.get("last name") 27 | u.email = row.get("email") 28 | u.save() 29 | return u 30 | 31 | def run(self, filepath, *args, **kwargs): 32 | progress_recorder = ProgressRecorder(self) 33 | dataframe = DataframeUtil.get_validated_dataframe(filepath) 34 | total_record = dataframe.shape[0] 35 | for index, row in dataframe.iterrows(): 36 | self.insert_into_row(row) 37 | progress_recorder.set_progress(index + 1, total=total_record, description="Inserting row into table") 38 | print("Inserting row %s into table" % index) 39 | 40 | return { 41 | "detail": "Successfully import user" 42 | } 43 | 44 | 45 | @celery_app.task(bind=True, base=ImportUserFromExcelTask) 46 | def import_user_task(self, *args, **kwargs): 47 | return super(type(self), self).run(*args, **kwargs) 48 | -------------------------------------------------------------------------------- /dj_celery_progress_sample/urls.py: -------------------------------------------------------------------------------- 1 | """dj_celery_progress_sample URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/3.1/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path("", views.home, name="home") 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path("", Home.as_view(), name="home") 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path("blog/", include("blog.urls")) 15 | """ 16 | from os import name 17 | 18 | from django.contrib import admin 19 | from django.urls import path 20 | 21 | from .views import (IndexTemplateView, download_file_view, export_user_view, 22 | get_progress_view, import_user_view) 23 | 24 | urlpatterns = [ 25 | path("admin/", admin.site.urls), 26 | path("", IndexTemplateView.as_view(), name="index"), 27 | path("export-user", export_user_view, name="export"), 28 | path("import-user", import_user_view, name="import"), 29 | path("celery-progress", get_progress_view, name="progress"), 30 | path("download-file", download_file_view, name="download"), 31 | ] 32 | -------------------------------------------------------------------------------- /dj_celery_progress_sample/utils.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from django.core.files.base import ContentFile 3 | from django.core.files.storage import default_storage 4 | 5 | 6 | class DataframeUtil(object): 7 | @staticmethod 8 | def get_validated_dataframe(path: str) -> pd.DataFrame: 9 | df = pd.read_excel(path, dtype=str) 10 | df.columns = df.columns.str.lower() 11 | df = df.fillna(-1) 12 | return df.mask(df == -1, None) 13 | 14 | 15 | def in_memory_file_to_temp(in_memory_file): 16 | path = default_storage.save('tmp/%s' % in_memory_file.name, ContentFile(in_memory_file.read())) 17 | return path 18 | -------------------------------------------------------------------------------- /dj_celery_progress_sample/views.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | from logging import raiseExceptions 4 | 5 | from celery_progress.backend import Progress 6 | from django.conf import settings 7 | from django.http import Http404, HttpResponse 8 | from django.views.generic import TemplateView 9 | 10 | from celery.result import AsyncResult 11 | 12 | from .forms import ImportFileForm 13 | from .tasks import export_user_task, import_user_task 14 | from .utils import in_memory_file_to_temp 15 | 16 | 17 | class IndexTemplateView(TemplateView): 18 | template_name = "index.html" 19 | 20 | 21 | def export_user_view(request): 22 | task = export_user_task.delay() 23 | return HttpResponse(json.dumps({"task_id": task.id}), content_type='application/json') 24 | 25 | 26 | def import_user_view(request): 27 | """ 28 | The column of the excel file should be part of 29 | [Username, Password, Email, First Name, Last Name] 30 | """ 31 | form = ImportFileForm(request.POST, request.FILES) 32 | if form.is_valid(): 33 | filepath = os.path.join( 34 | settings.MEDIA_ROOT, in_memory_file_to_temp(form.cleaned_data.get('document_file')) 35 | ) 36 | task = import_user_task.delay(os.path.join(settings.MEDIA_ROOT, filepath)) 37 | return HttpResponse(json.dumps({"task_id": task.id}), content_type='application/json') 38 | raise Http404 39 | 40 | 41 | def get_progress_view(request): 42 | progress = Progress(request.GET.get("task_id")) 43 | return HttpResponse(json.dumps(progress.get_info()), content_type='application/json') 44 | 45 | 46 | def download_file_view(request): 47 | celery_result = AsyncResult(request.GET.get("task_id")) 48 | filepath = celery_result.result.get("data", {}).get("outfile") 49 | if os.path.exists(filepath): 50 | with open(filepath, 'rb') as fh: 51 | response = HttpResponse(fh.read(), content_type="application/ms-excel") 52 | outfile = os.path.basename(filepath) 53 | response['Content-Disposition'] = "attachment; filename=%s" % outfile 54 | return response 55 | raise Http404 56 | -------------------------------------------------------------------------------- /dj_celery_progress_sample/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for dj_celery_progress_sample project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.1/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dj_celery_progress_sample.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dj_celery_progress_sample.settings') 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == '__main__': 22 | main() 23 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | amqp==5.0.1 2 | asgiref==3.2.10 3 | autopep8==1.5.4 4 | billiard==3.6.3.0 5 | celery==5.0.0 6 | celery-progress==0.0.12 7 | click==7.1.2 8 | click-didyoumean==0.0.3 9 | click-repl==0.1.6 10 | Django==3.1.2 11 | django-cors-headers==3.5.0 12 | django-extensions==3.0.9 13 | et-xmlfile==1.0.1 14 | importlib-metadata==2.0.0 15 | jdcal==1.4.1 16 | kombu==5.0.2 17 | numpy==1.19.2 18 | openpyxl==3.0.5 19 | pandas==1.1.3 20 | prompt-toolkit==3.0.7 21 | pycodestyle==2.6.0 22 | python-dateutil==2.8.1 23 | pytz==2020.1 24 | redis==3.5.3 25 | six==1.15.0 26 | sqlparse==0.3.1 27 | toml==0.10.1 28 | vine==5.0.0 29 | wcwidth==0.2.5 30 | xlrd==1.2.0 31 | zipp==3.2.0 32 | -------------------------------------------------------------------------------- /runcelery.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | celery -A dj_celery_progress_sample worker --loglevel=DEBUG -------------------------------------------------------------------------------- /static/docs/users-template.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebysofyan/django-celery-progress-sample/311289c01a6d603daafd804d30699b0019e47409/static/docs/users-template.xlsx -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | 4 | 5 |
6 | 7 | 8 |