我用的是Django 2.2.5,芹菜5.2.6和RabbitMQ,我对最后的2种还很陌生。
我想要生成一个Excel表,并将它存储在新创建的对象中的一个FileField中(而不是下载它),这就是我所做的:
项目/设置.project:
CELERY_RESULT_BACKEND = "django-db"
CELERY_CACHE_BACKEND = "django-cache"
CELERY_BROKER_URL = "amqp://localhost"
CELERY_ACCEPT_CONTENT = ["application/json"]
CELERY_TASK_SERIALIZER = "json"
CELERY_RESULT_SERIALIZER = "json"
CELERY_TIMEZONE = "Africa/Casablanca"项目/celery.py:
from __future__ import absolute_import, unicode_literals
import os
from celery import Celery
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "verautonoapi.settings")
app = Celery("verautonoapi")
app.config_from_object("django.conf:settings", namespace="CELERY")
app.autodiscover_tasks()
@app.task(bind=True)
def debug_task(self):
print("Request: {0!r}".format(self.request))project/init.py:
from __future__ import absolute_import, unicode_literals
# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from .celery import app as celery_app
__all__ = ("celery_app",)app/tasks.py:
from __future__ import absolute_import, unicode_literals
from django.http import HttpResponse, FileResponse
from celery import shared_task
from celery.utils.log import get_task_logger
from time import sleep
from openpyxl import Workbook
from datetime import date
from .models import Dossier, Export
logger = get_task_logger(__name__)
@shared_task(bind=True, track_started=True)
def exp_en_cours(request):
print("task activated")
sleep(7)
print("now starting generating the file")
dossier_queryset = Dossier.objects.filter(status_admin="Validation OR Requise")
today = str(date.today())
response = FileResponse(
content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
)
response["Content-Disposition"] = (
"attachment; filename=" + today + "-dossiers_en_cours.xlsx"
)
workbook = Workbook()
# Get active worksheet/tab
worksheet = workbook.active
worksheet.title = "Dossiers en cours"
# Define the titles for columns
columns = [
"Numéro",
"Créé le",
"Assurance",
"Prestataire",
"Matricule",
]
row_num = 1
# Assign the titles for each cell of the header
for col_num, column_title in enumerate(columns, 1):
cell = worksheet.cell(row=row_num, column=col_num)
cell.value = column_title
# Iterate through all movies
for dossier in dossier_queryset:
row_num += 1
# Define the data for each cell in the row
row = [
dossier.numero,
str(dossier.date_posted)[:10],
dossier.assurance.name,
dossier.created_by.user.username,
dossier.matricule,
]
# Assign the data for each cell of the row
for col_num, cell_value in enumerate(row, 1):
cell = worksheet.cell(row=row_num, column=col_num)
cell.value = cell_value
workbook.save(response)
Export.objects.create(status="Dossier en cours", file=response)
return "OK"app/models.py s.py:
class Export(models.Model):
STATUS = [
("Dossier en cours", "Dossier en cours"),
("Dossier validés", "Dossier validés"),
("Dossier rejetés", "Dossier rejetés"),
("Dossier à clôturer", "Dossier à clôturer"),
("Dossier clôturés", "Dossier clôturés"),
("Dossier facturés", "Dossier facturés"),
("Dossier archivés", "Dossier archivés"),
]
status = models.CharField(max_length=20, choices=STATUS, null=True, blank=True)
timestamp = models.DateTimeField(auto_now_add=True, editable=False)
file = models.FileField(
upload_to=get_rapport_filename, verbose_name="Fichiers Excel"
)
def __str__(self):
return "%s - %s" % (self.dossier, self.timestamp)
class Meta:
verbose_name = "Rapport Excel"
verbose_name_plural = "Rapports Excel"我还安装了django_celery_results并将其添加到已安装的应用程序中。
当我执行任务时,它会出现以下错误:
This FileResponse instance is not writable

我在Windows和Linux上(在数字海洋上)都试过了,我也得到了同样的错误。你能告诉我我做错了什么吗?excel函数不正确吗?因为我确实对其进行了修改,以防止其下载(将HttpResponse替换为FileResponse)。或者是RabbitMQ和芹菜?
更新:问题在于Excel函数,而不是芹菜/RabbitMQ。我复制了任务并将其作为常规视图放置,并获得了相同的错误。
UPDATE 2:我修改了视图,使其能够以BytesIO流的形式获取文件,并使用ContentFile将其放入模型中,并且能够下载该文件,但它不能打开:
views.py:
dossier_queryset = Dossier.objects.filter(status_admin="Validation OR Requise")
# today = str(date.today())
# response = FileResponse(
# content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
# )
# response["Content-Disposition"] = (
# "attachment; filename=" + today + "-dossiers_en_cours.xlsx"
# )
workbook = Workbook()
# Get active worksheet/tab
worksheet = workbook.active
worksheet.title = "Dossiers en cours"
# Define the titles for columns
columns = [
"Numéro",
"Créé le",
"Assurance",
"Prestataire",
"Matricule",
]
row_num = 1
# Assign the titles for each cell of the header
for col_num, column_title in enumerate(columns, 1):
cell = worksheet.cell(row=row_num, column=col_num)
cell.value = column_title
# Iterate through all movies
for dossier in dossier_queryset:
row_num += 1
# Define the data for each cell in the row
row = [
dossier.numero,
str(dossier.date_posted)[:10],
dossier.assurance.name,
dossier.created_by.user.username,
dossier.matricule,
]
# Assign the data for each cell of the row
for col_num, cell_value in enumerate(row, 1):
cell = worksheet.cell(row=row_num, column=col_num)
cell.value = cell_value
vworkbook = BytesIO()
workbook.save(vworkbook)
content = vworkbook.getvalue()
b64 = base64.b64encode(content)
file = (
"data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,"
+ str(b64)
)
format, filestr = file.split(";base64,")
# ext = format.split("/")[-1]
ext = ".xlsx"
Export.objects.create(
status="Dossier en cours",
file=ContentFile(base64.b64decode(filestr), name="temp." + ext),
)
return redirect("homepage")发布于 2022-05-23 01:46:24
以下是解决办法:
from io import BytesIO
from django.core.files.base import ContentFile
vworkbook = BytesIO()
workbook.save(vworkbook)
content = vworkbook.getvalue()
try:
Export.objects.create(
status="Dossiers archivés",
file=ContentFile(
content, name="dossiers_archivés-" + str(date.today()) + ".xlsx"
),
)
return "EXP_ARCH OK"
except Exception:
raise Exceptionhttps://stackoverflow.com/questions/72334113
复制相似问题