Я сейчас пытаюсь выучить джанго.Я работаю над личным проектом.Я пытаюсь создать действие в панели администратора для извлечения данных из моей модели в файл CSV.Например, у меня есть следующая модель:
class OrderItem(models.Model):
order = models.ForeignKey(Order, related_name='items', on_delete=models.CASCADE)
type_product = models.ForeignKey(Sous_Categories_Article, verbose_name="Catégorie Article", on_delete=models.PROTECT)
product = models.ManyToManyField(Variations_Articles, max_length=1000, verbose_name='Article')
price = models.DecimalField(max_digits=10, decimal_places=2)
quantity = models.PositiveIntegerField(default=1)
В то время я использую следующий код:
def export_to_csv(modeladmin, request, queryset):
opts = modeladmin.model._meta
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename=%s.csv' % str(opts).replace('.', '_')
writer = csv.writer(response, delimiter=";")
fields = []
fields = [field for field in opts.get_fields()]
writer.writerow([field.name.title() for field in fields])
for obj in queryset:
data_row = []
for field in fields:
if field.many_to_many == True or field.one_to_many == True:
try:
value = list(getattr(obj,field.name).all().values_list('id', flat=True))
except:
value = str(obj).replace(";", "")
else:
value = str(getattr(obj, field.name)).replace(";", "")
if isinstance(value, datetime.datetime):
value = value.strftime('%d/%m/%Y')
data_row.append(value)
writer.writerow(data_row)
return response
export_to_csv.short_description = 'Экспорт в CSV'
У меня есть два вопроса.Мне нравится извлекать другие модели, в которых есть поле ManyToManyField или поле «один ко многим».Как я могу продолжить?Следующий код относится только к конкретной модели:
values = obj.product.all().values_list('id', flat=True)
Как использовать «переменную» в своем запросе вместо дублирования кода для каждой модели?
Мой второй вопрос касаетсясоздавая новую строку каждый раз, когда в поле многие ко многим есть несколько записей.Например, как упоминалось выше, заказ может иметь несколько продуктов.Я хотел бы создать новую строку для каждого продукта в заказе (дублируя данные):
Order 1 Type_Product Quantity Price Product 1
Order 1 Type_Product Quantity Price Product 2
В то время я смог создать одну строку:
Order 1 Type_Product Quantity Price Product 1 Product 2
Спасибо за вашу помощь,
Singertwist
Вопрос 2: решение (не самое лучшее, но работающее)
def export_to_csv_sales(modeladmin, request, queryset):
opts = modeladmin.model._meta
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename=%s.csv' % str(opts).replace('.', '_')
writer = csv.writer(response, delimiter=";")
# fields = [field for field in opts.get_fields() if not field.many_to_many and not field.one_to_many]
fields = []
fields = [field for field in opts.get_fields()]
# Write a first row with header information
# writer.writerow([field.verbose_name.title() for field in fields]) # Title nécessaire car sinon ID est le premier champ et provoque un avertissement lors de l'ouverture sous Excel( fichier de type Sylk).
writer.writerow([field.name.title() for field in fields])
# Write data rows
for obj in queryset:
data_row = []
for field in fields:
if field.many_to_many == True or field.one_to_many == True:
try:
values = list(getattr(obj, field.name).all().values_list('id', flat=True)) # On récupérère sous forme de liste les id relatifs aux articles.
except:
value = str(obj).replace(";", "") # Replace permet de supprimer les point virgule des chaines de caractères afin de ne pas interférer avec le séparateur du CSV.
else:
value = str(getattr(obj, field.name)).replace(";", "") # Replace permet de supprimer les point virgule des chaines de caractères afin de ne pas interférer avec le séparateur du CSV.
if isinstance(value, datetime.datetime):
value = value.strftime('%d/%m/%Y')
data_row.append(value) # On aggrège toutes les données d'une ligne dans la liste data_row.
# Si values est différent de None, cela veut dire que l'on a une liste présente dans la commande. Donc une composition. On va créé pour une ligne pour chaque item de la composition.
if values != None:
for data in values: # On parcours la liste contenant les différents ingrédients de la commande.
data_row[-1] = data # On remplace la liste par les données de la liste. Pour sélectionner la dernière colonne contenant les produits, on utilise l'index [-1], le -1 signifie que l'on sélection la première colonne en partant de la fin.
writer.writerow(data_row) # On écrit une ligne avec l'ID qui a été inséré
else:
writer.writerow(data_row) # S'il n'y a pas de composition on écrit la ligne normalement.
return response
export_to_csv_sales.short_description = 'Exporter au format CSV'