ValueError:在使用这种多对多关系之前,变量需要具有字段“ id”的值-Django

时间:2018-09-28 20:28:02

标签: database django-models python-3.4 valueerror django-1.11

我在Django中创建了一个数据模型,现在我创建了一个脚本,使用网络抓取的值自动填充模型。但是,当我运行脚本时,出现以下错误: ValueError:在使用这种多对多关系之前,变量必须具有字段“ id”的值

Models.py

class Books(models.Model):
    title = models.CharField(max_length=100)

    def __str__(self):
        return self.title

    class Meta:
        ordering = ['-title']

class Author(models.Model):
    book = models.ManyToManyField(Books)
    first_name = models.CharField(max_length=150)
    last_name = models.CharField(max_length=200)

    def __str__(self):
        return "{} {}".format(self.first_name, self.last_name)

    class Meta:
        ordering = ['last_name','first_name']


class Book_details(models.Model):
    book = models.ForeignKey(Books, 
                            on_delete=models.CASCADE, 
                            null=True) # models.SET_NULL weggehaald
    pages = models.CharField(max_length=250)
    publ_year = models.CharField(max_length=250)
    edition = models.CharField(max_length=30) # paperback, hardcover, audiobook, etc


    def __str__(self):
        return "{} - pages: <{}>, edition: <{}>".format(self.book.title, 
                                                    self.pages, 
                                                    self.edition)# 

class Cover(models.Model):
    book = models.OneToOneField(Books, 
                            on_delete=models.CASCADE)
    path = models.CharField(max_length=500)

    def __str__(self):
        return "<Cover <path={}>".format(self.id, self.path)

populate_script

def add_book(title):
    b = Books.objects.get_or_create(title = title)[0]
    print(b)
    b.save()
    return b

def populate(scraped_tuple):
    fake = Faker()

    for _ in range(len(scraped_tuple)):

        b_title = scraped_tuple[_][0][0]
        new_book = add_book(b_title)

        b_author_first = scraped_tuple[_][0][1].split(" ")[0]
        b_author_last = scraped_tuple[_][0][1].split(" ")[1]
        b_pages = scraped_tuple[_][0][2].split(" ")[0]
        b_publ_year = fake.year()
        b_edition = scraped_tuple[_][0][3].split(",")[0]
        b_cover = scraped_tuple[_][0][4]

        new_details = Book_details.objects.get_or_create(book = new_book, pages = b_pages, publ_year = b_publ_year, edition = b_edition)[0]

        new_author = Author.objects.get_or_create(book = new_book, first_name = b_author_first, last_name = b_author_last)[0]

        new_cover = Cover.objects.get_or_create(book = new_book, path = b_cover)[0]

scraped_tuple是网络爬虫的返回值,其中包含详细信息。

(部分)回溯:

Books.models.DoesNotExist: Author matching query does not exist.
  File "C:\path\to\LibraryApp\Library_WebA
pp\Library\populate.py", line 45, in populate
    new_author = Author.objects.get_or_create(book = new_book, first_name = b_author_first, last_nam
e = b_author_last)[0]

其次:

ValueError: "<Author: Mary McCarthy>" needs to have a value for field "id" before this many-to-many relationship can be used.

因此,由于Author模型中的“多对多”字段“ book”,在尝试执行new_author语句时似乎出现了一些错误。我该如何解决。我是否需要对Author对象类似的功能,就像在add_book()中对Book一样? 似乎new_details语句执行得很好(title和book_details在Django的admin部分的数据库中正确显示)。

1 个答案:

答案 0 :(得分:1)

docs中所述,用户.add()可以将记录关联到多对多字段。

def populate(scraped_tuple):
fake = Faker()

for _ in range(len(scraped_tuple)):

    b_title = scraped_tuple[_][0][0]
    new_book = add_book(b_title)

    b_author_first = scraped_tuple[_][0][1].split(" ")[0]
    b_author_last = scraped_tuple[_][0][1].split(" ")[1]
    b_pages = scraped_tuple[_][0][2].split(" ")[0]
    b_publ_year = fake.year()
    b_edition = scraped_tuple[_][0][3].split(",")[0]
    b_cover = scraped_tuple[_][0][4]

    new_details = Book_details.objects.get_or_create(book = new_book, pages = b_pages, publ_year = b_publ_year, edition = b_edition)[0]

    new_author = Author.objects.get_or_create(first_name = b_author_first, last_name = b_author_last)[0]

    # add many to many fields this way:
    new_author.book.add(new_book)

    new_cover = Cover.objects.get_or_create(book = new_book, path = b_cover)[0]