0

I don't seem to understand this error or how to fix it. There's something I don't understand about django models.

Consider what happens when I try to perform get_or_create on the Keyword model. Here's the model, alongside some code I write in shell.

@python_2_unicode_compatible
class Keyword(models.Model):
    word      = models.CharField(max_length=200)
    statement = models.ManyToManyField(Statement)
    def __str__(self):
        return self.word


>>> from gtr_site.models import *
>>> a = Statement()
>>> Keyword.objects.get_or_create(word="Testkeyword", statement=a)
Traceback (most recent call last): ...
ValueError: "<Keyword: Testkeyword>" needs to have a value for field "keyword" before this many-to-many relationship can be used.

But if you simply write Keyword.objects.get_or_create(word="TestKeyWord") (so if you exclude the statement instance entirely), then the error disappears.

I really don't understand how this error can be occurring because... Neither the Statement model nor the Keyword model actually have a field called "keyword."

However, the Statement model does have a lot of components. Here's the code for it.

@python_2_unicode_compatible
class Statement(models.Model):
    statement_id = models.CharField(max_length=200)
    title = models.CharField(max_length=200)
    issue_date = models.DateField("Issue-Date")
    author = models.ForeignKey(Person)
    released_by = models.ForeignKey(Organization)
    keywords = models.ManyToManyField('KeywordInContext')
    solokeywords = models.ManyToManyField('Keyword', related_name='statement_keywords')

There's three more choice fields in the model that I chose to exclude for the sake of clarity.

There's only one field in the Statements model that actually does have a field called keyword. The field "keywords" which creates a ManyToMany relationship with KeywordInContext This model is as follows:

 @python_2_unicode_compatible
 class KeywordInContext(models.Model):
    keyword = models.ForeignKey(Keyword)
    contexts = models.ManyToManyField(Keyword, related_name='keyword_context')

 def __str__(self):
    return self.keyword.word + ' (' + ', '.join(c.word for c in self.contexts.all()) + ')'

Important to note is that the field keyword makes a ForeignKey to a Keyword object.

So... I still don't understand how this is happening. When I am trying to create new Keyword that has both of its word and statement field's as parameters, I don't understand why a field from KeyInContext even becomes relevant. With respect to that, how do I create a Keyword object with both of its word and statement parameters specified?

Byron Smith
  • 587
  • 10
  • 32

1 Answers1

1

The error is trying to tell you that you need to save the Keyword object before you can link to it via a many-to-many. You will also need to save the Statement; this is because an m2m relationship involves a linking table, so both sides need IDs before you can link them. In other words, you can't assign an m2m field in the create call.

As to why you get that particular message, I guess you have an old version of the models in memory where you defined the primary key field as keyword.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • Hi. I started doing some testing that actually was suggesting exactly what you said. but .save() isn't working quite in context. I perform `Statement.objects.update_or_create()` (albeit currently, I don't save the instance upon update or creation). Then what follows is I get the Statement object that was just updated or created. `cur_statement = Statement.objects.get_or_create(statement_id = statement["statement_id"])` But if I try to save it... `cur_statement.save()` gives error `'tuple' object has no attribute 'save'` – Byron Smith Aug 05 '17 at 17:22
  • Nevermind. I made it work exactly as desired. I will go provide an answer with the code that I used (or to summarize basically) – Byron Smith Aug 05 '17 at 17:36
  • Dumb error on my part. Spent a day not realizing you can't assign m2m objects in a create call. – Byron Smith Aug 05 '17 at 17:36