6

I was confused to why when I run this code it returns an error

create() takes 1 positional argument but 2 were given

if request.method == "POST":
my_form = RawProductCreateForm(request.POST)
if my_form.is_valid():
    Product.objects.create(my_form.cleaned_data)

but when I modify on the create method and add ** before passing the cleaned data it works!

Product.objects.create(**my_form.cleaned_data)
Ayyoub
  • 4,581
  • 2
  • 19
  • 32
  • post the model and the form too – Exprator Sep 10 '19 at 06:02
  • 1
    Read the docs on `objects.create`: https://docs.djangoproject.com/en/2.2/ref/models/querysets/#create It only takes keyword arguments in the form of `model_prop=value` and no positional arguments. The `**` operator in python applies the dictionary as keyword arguments to the function. See https://stackoverflow.com/questions/36901/what-does-double-star-asterisk-and-star-asterisk-do-for-parameters. – azundo Sep 10 '19 at 06:04
  • 1
    If your `RawProductCreateForm` is a `ModelForm`, you could use [the save method](https://docs.djangoproject.com/en/2.2/topics/forms/modelforms/#the-save-method) to create the Product object e.g. `my_form.save()` – AKS Sep 10 '19 at 06:16

3 Answers3

11

It is because create takes keyword arguments, like

    Product.objects.create(product_name="Dish Soap", product_price=73)

Placing the ** before it tells the model to treat my_form.cleaned_data as a dictionary of keyword arguments.

Matthew Gaiser
  • 4,558
  • 1
  • 18
  • 35
3

The create function under the hood looks more less like this:

def create(self, **data):
   pass

As you can see you have one positional argument self, other one is just a key words dictionary. When you call this function like this:

Product.objects.create(my_form.cleaned_data)

You are passing two positional arguments one is objects this is how python handle classes and methods and other one is my_form.cleaned_data, but the function exptes only one positional and any numbers of named arguments. In second call:

Product.objects.create(**my_form.cleaned_data)

lets say the my_form.cleaned_data looks like this:

{ 
  'age': 1,
  'name': 'good product'
}

so the equvialent of the second call would be

Product.objects.create(name='good product', age=1)

As you can see you have only one positional argument objects and 2 named arguments. In create function you can refer to data like this:

def create(self, **data):
   name = data['name']
   age = data['age']
0

This happens when you try to insert data without a point to the field defined in the model. To fix this you have to pass field name inside the create() with assignment operator.

Product.objects.create(field1="<field 1 data>", field2=<field2 data>)
Mayur
  • 4,345
  • 3
  • 26
  • 40