【问题标题】:Extracting Admin ManyToManyField to CSV file将 Admin ManyToManyField 提取到 CSV 文件
【发布时间】:2019-02-22 20:29:01
【问题描述】:

我目前正在尝试学习 django。我正在做一个个人项目。 我正在尝试在管理面板中创建一个操作,用于将数据从我的模型中提取到 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 或 One to Many Field 的其他模型。 我该如何进行? 以下代码仅适用于特定模型:

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

感谢您的帮助,

曲风

问题 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'

【问题讨论】:

    标签: django django-admin export-to-csv django-admin-actions


    【解决方案1】:

    对于你的第一个问题:你试过这个吗?

    values = getattr(obj, field_name).all().values_list('id', flat=True)
    

    您应该在您的代码中获得field_name。我想你有它。

    【讨论】:

    • 感谢您的帮助。有用。我用解决方案更新我的代码。您知道我如何为每种产品创建生产线吗?提前感谢您的帮助。
    • 嗨@singertwist,你知道第二个问题该怎么做吗?
    • 是的,我想出了点什么,不是最好的办法。但它适用于这种情况。我已经更新了我的代码。
    猜你喜欢
    • 2022-01-05
    • 2015-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-08
    • 2012-04-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多