Django:从具有ForeignKey的CSV创建对象

时间:2019-04-09 20:09:58

标签: python django

我有2种型号:CategoryProduct,并且我都需要从CSV文件中上传两者。

Category模型上传CSV数据时,我可以这样做,因为它没有ForeignKey字段。

但是尝试从Product模型从CSV上载数据时出现错误。因为它具有Category模型的ForeignKey。

  

ValueError:无法分配“'Stickers'”:“ Product.category”必须为   “类别”实例。

有可能吗?我可以将该字段保留为空白,以后不要求手动进行此操作,但是理想的情况是自动执行此操作。

commands / products.py

import pandas as pd
import csv
from shop.models import Product
from django.core.management.base import BaseCommand


tmp_data_products=pd.read_csv('static/data/products.csv',sep=',', encoding="utf-8").fillna(" ")


class Command(BaseCommand):
    def handle(self, **options):
        products = [
            Product(
                category=row['category'],
                product=row['product'],
                slug=row['slug'],
                description=row['description'],
                size=row['size'],
                quantity =row['quantity'],
                price=row['image'],
                available=row['available']
        )
            for _, row in tmp_data_products.iterrows()
        ]

        Product.objects.bulk_create(products)

models.py:

class Category(models.Model):
    category = models.CharField(max_length=250, unique=True)
    slug = models.SlugField(max_length=250, unique=True)
    description = models.TextField(blank=True, null=True)
    image = models.ImageField(upload_to='category', blank=True, null=True)
    video = EmbedVideoField(null=True, blank=True)

class Product(models.Model):
    product = models.CharField(max_length=250, unique=True)
    slug = models.SlugField(max_length=250, unique=True)
    description = models.TextField(blank=True)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    size = models.CharField(max_length=20, choices=TAMANIOS)
    quantity = models.CharField(max_length=20, choices=CANTIDADES)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    image = models.ImageField(upload_to='product', blank=True, null=True)
    available = models.BooleanField(default=True)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

更新1:

categories.csv

| category  | slug      | description                                                          | image | video |
|-----------|-----------|----------------------------------------------------------------------|-------|-------|
| Imantados | imantados | Los mejores imantados en vinyl,   acabado mate. Resistentes al agua. |       |       |
| Stickers  | stickers  | Los mejores stickers en vinyl,   acabado mate. Resistentes al agua.  |       |       |
| Muestras  | muestras  | Los mejores stickers en vinyl,   acabado mate. Resistentes al agua.  |       |       |

products.csv

| category | product                | slug                   | description                                                           | size      | quantity | price | image | available |
|----------|------------------------|------------------------|-----------------------------------------------------------------------|-----------|----------|-------|-------|-----------|
| Stickers | Stickers transparentes | stickers-transparentes | Stickers Transparentes en Vinyl de alta calidad. Resistentes al agua. | 5cm x 5cm | 50       | 50    |       | True      |
| Stickers | Stickers transparentes | stickers-transparentes | Stickers Transparentes en Vinyl de alta calidad. Resistentes al agua. | 5cm x 5cm | 100      | 70    |       | True      |
| Stickers | Stickers transparentes | stickers-transparentes | Stickers Transparentes en Vinyl de alta calidad. Resistentes al agua. | 5cm x 5cm | 200      | 90    |       | True      |
| Stickers | Stickers transparentes | stickers-transparentes | Stickers Transparentes en Vinyl de alta calidad. Resistentes al agua. | 5cm x 5cm | 300      | 120   |       | True      |
| Stickers | Stickers transparentes | stickers-transparentes | Stickers Transparentes en Vinyl de alta calidad. Resistentes al agua. | 5cm x 5cm | 500      | 140   |       | True      |
| Stickers | Stickers transparentes | stickers-transparentes | Stickers Transparentes en Vinyl de alta calidad. Resistentes al agua. | 5cm x 5cm | 1000     | 200   |       | True      |
| Stickers | Stickers transparentes | stickers-transparentes | Stickers Transparentes en Vinyl de alta calidad. Resistentes al agua. | 5cm x 5cm | 2000     | 300   |       | True      |
| Stickers | Stickers transparentes | stickers-transparentes | Stickers Transparentes en Vinyl de alta calidad. Resistentes al agua. | 7cm x 7cm | 50       | 70    |       | True      |
| Stickers | Stickers transparentes | stickers-transparentes | Stickers Transparentes en Vinyl de alta calidad. Resistentes al agua. | 7cm x 7cm | 100      | 90    |       | True      |
| Stickers | Stickers transparentes | stickers-transparentes | Stickers Transparentes en Vinyl de alta calidad. Resistentes al agua. | 7cm x 7cm | 200      | 130   |       | True      |

1 个答案:

答案 0 :(得分:3)

就像错误提示一样,您必须先从数据库中获取相应的对象才能进行分配:

category = Category.objects.get(id=row['category'])

但是有一个快捷方式:

category_id = row['category']

注意_id,可让您直接分配外键(=所引用对象的主键)。

使用此功能时,在将对象写入数据库之前,您显然不会注意到无效的外键。


如果您的CSV文件中确实有类别名称而不是ID,那么您肯定首先需要找到相应的数据库对象:

category = Category.objects.get(category=row['category'])

您可以将其包装在try / except中,以准备缺少的类别;幸运的是,类别名称上有一个唯一的约束,因此,多个具有相同名称的对象将不会成为问题。