Bill Noble Bill Noble - 8 months ago 40
Python Question

Django: using ManyToMany-field as keyword during object creation causes TypeError

When running a Django model create call I get an error message as follows:

TypeError: 'keywords' is an invalid keyword argument for this function

The create object is called form within a ModelViewset and looks like this:

the_item = Item.objects.create(url=the_photo_url, owner=the_user, keywords=the_keywords, item_type=the_item_type, title=the_title)

My Item model looks like this (it has a keywords field that links to a keyword table):

class Item(models.Model):

('V', 'Vine'),
('Y', 'YouTube'),
('P', 'Photo'), # Photo is stored by us on a CDN somewhere
('F', 'Flickr'),
('I', 'Instagram'),
('D', 'DeviantArt'),
('5', '500px'),
owner = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=60, default='')
url = models.CharField(max_length=250, default='', unique=True)
item_type = models.CharField(max_length=1, choices=ITEM_TYPES)
keywords = models.ManyToManyField(Keyword, related_name='keywords')
credits_applied = models.IntegerField(default=5000)
credits_left = models.IntegerField(default=10)
credits_gifted = models.IntegerField(default=0)
date_added = models.DateTimeField(auto_now_add=True)
liked = models.IntegerField(default=0)
disliked = models.IntegerField(default=0)
active = models.BooleanField(default=True)
comment = models.CharField(max_length=100, blank=True)
approved = models.BooleanField(default=0)

The related Keyword model looks like this:

class Keyword(models.Model):
name = models.CharField(max_length=30)

argument to the
is a Python list:

Why is Django complaining about the Keywords parameter?


You cannot use a ManyToMany field like that in the creation of a Model instance. For the creation of the necessary through model instances, the object must be saved first (to have a pk). So create the instance first, and then use the add method to add Keyword instances (you can do so with multiple at a time):

the_item = Item.objects.create(...)  

keywords = list(Keyword.objects.filter(id__in=[1, 21]))

Or, maybe a little more performant, using the through model and bulk_create directly will reduce the entire adding to one db hit:

kw_ids = [1, 21]
through_model = Item.keywords.through
    [through_model(, keyword_id=kw_id) for kw_id in kw_ids]