Как создать несколько объектов с разными значениями одновременно в django?

#python #django #django-views #django-templates

#python #django #django-представления #django-шаблоны

Вопрос:

Мне нужно создать две модели из одного шаблона. Создание модели продукта — это нормально. Модель продукта имеет отношение ManyToOne к ProductVariant. Но у меня возникла проблема при создании модели ProductVariant. request.POST.getlist('names') это дает мне такой результат ['name1','name2 ] и то же самое касается всех. Я хочу создать объект ProductVariant с каждым значением. Как я могу это сделать? Также я думаю, что есть проблема при построении a HStoreField . request.POST.getlist('attributes') выдает значение, подобное этому ['a:b','x:z'] , поэтому я преобразовал его в dictionary (но не уверен, что это работает).

Обновить:

Я хочу attributes , names … у всех будет одинаковое количество элементов в списке. Например, если имя ['a','b','c'] , то вес также будет иметь 3 значения в списке [12,15,23] , подобном этому. Я хочу создать ProductVariant объект 3 раза, так как в каждом списке будет 3 элемента в списке. Первый объект будет иметь значения полей из первого элемента списка, name=a,weight=12.. а для второго значения объекта будут name=b, weight=15 такими.

Как это будет возможно? Или я должен изменить логику? Есть предложения? Модели

 class ProductVariant(models.Model):
    name = models.CharField(max_length=255, blank=False, null=False)
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    attributes = HStoreField()
    price = models.FloatField(blank=False, null=False, default=0.0) 
  

число просмотров

         product = product_form.save()           
        attributes = request.POST.getlist('attributes')
        names = request.POST.getlist('name')
        up = request.POST.getlist('price')
        weight = request.POST.getlist('weight')
        print(names, 'names')
        # converting attributes into the dictionary for the HStore field
        for attribute in attributes:
            attributes_dict = {}
            key, value = attribute.split(':')
            attributes_dict[key] = value
        
       ProductVariant.objects.create(name=name,...) # for each value I want to create this.
  

Ответ №1:

Ответ на обновление:

 names = ['a', 'b', 'c']
weights = [12, 15, 23]

params = zip(names, weights)
products = [ProductVariant(name=param[0], weight=param[1]) for param in params]
ProductVariant.objects.bulk_create(products)
  

Комментарии:

1. пожалуйста, обратитесь к публикации 1 ответа, если у вас есть несколько методов, вместо публикации нескольких ответов

Ответ №2:

Я не согласен с этим подходом, но если вы действительно хотите сделать это таким образом, zip ing будет таким, как указал @forkcs.

Я бы использовал Django, чтобы помочь мне как можно больше, прежде чем я туда доберусь, пожалуйста, внесите это изменение. float ! = деньги

 class ProductVariant(models.Model):
    name = models.CharField(max_length=255, blank=False, null=False)
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    attributes = HStoreField()
    price = models.DecimalField(blank=False, null=False, default=0, max_digits=6, decimal_places=2)
  

Как только это будет сделано, форма должна выглядеть следующим образом:

 class ProductVariantForm(forms.ModelForm):
    class Meta:
        fields = ('name', 'product', 'attributes', 'price')
        model = ProductVariant


ProductVariantFormSet = formset_factory(ProductVariantForm)
  

Обратите внимание, что мне не нужно анализировать / очищать / форматировать attributes ? Это потому, что Django сделал это за меня 😉

И вы можете использовать это следующим образом, если вы изменяете свои поля и не используете одно и то же имя несколько раз: (вместо того, чтобы все ваши поля назывались «атрибутами», вы называете их «form-X-attributes», где X — число 0-бесконечность, пример)

     product = product_form.save()    
    formset = ProductVariantFormSet(data=request.POST)
    if formset.is_valid():
        instances = []
        for form in formset:
            if form.is_valid():  # this could probably be removed
                instances.append(form.save())
  

Для дополнительного кредита вы также можете сделать: (это не должно иметь большого значения)

     product = product_form.save()    
    formset = ProductVariantFormSet(data=request.POST)
    if formset.is_valid():
        instances = []
        for form in formset:
            if form.is_valid():  # this could probably be removed
                instances.append(form.save(save=False))
        ProductVariant.objects.bulk_create(instances)
  

Что вы получаете? СТАНДАРТЫ!!! И разделение! Все, кто знает Django, знают, что вы сделали. Вся ваша чистая логика будет размещена в нужном месте (форме), и вы будете менее подвержены ошибкам.

Ps. я написал тесты для вас. https://gist.github.com/kingbuzzman/937a9d207bd937d1b2bb22249ae6bdb2#file-formset_example-py-L142 Если вам нужна дополнительная информация о моем подходе, обратитесь к документации https://docs.djangoproject.com/en/3.1/topics/forms/formsets /

Комментарии:

1. Будут ли какие-либо проблемы, zip поскольку это только что решило мою проблему. В любом случае спасибо за информацию, и я тоже попробую этот способ.

2. Да, есть проблема, вам приходится слишком много выполнять вручную, заботиться об очистке, проверке ошибок … и т.д. Кроме этого, проблем нет 😜

3. @helloworld я предлагаю вам взглянуть на youtu.be/Uwuv05aZ6ug?t=361 — первая часть выступления — это то, что имеет отношение к тому, что я предлагаю — речь идет о законе Миллера (в целом выступление отличное).

Ответ №3:

Что касается атрибутов, их можно было бы сократить до одной строки следующим образом:

 attributes_dict = dict(map(lambda x: x.split(':'), attributes))
  

Чтобы создать несколько объектов, вы должны либо выполнять итерации и создавать по одному объекту за раз, либо использовать bulk_create :

 for name in names:
    ProductVariant.objects.create(name=name,...)
  

Или

 ProductVariant.objects.bulk_create([ProductVariant(name=name) for name in names])
  

Комментарии:

1. Я должен использовать for loop не только для name, но и для других значений.

2. Могу ли я использовать другие циклы после массового создания for name in names ?

3. Нравится это? ProductVariant.objects.bulk_create([ProductVariant(name=name, price=p) for name in names for p in up])

4. Тогда сформулируйте свой вопрос лучше. Вы можете использовать все, что хотите, в цикле for, никто и ничто вас не держит. Пожалуйста, прочитайте документы: docs.djangoproject.com/en/3.1/ref/models/querysets/#bulk-create

5. Затем еще раз лучше опишите свою проблему. Обновите сообщение, укажите проблему, покажите журналы, объясните желаемый результат.

Ответ №4:

Наилучшей практикой для этого является использование bulk_create метода.

 product_variants = [ProductVariant(name=name) for name in names]
ProductVariant.objects.bulk_create(product_variants)