1

I am trying to create a Many-To-Many relationship between two models- Author and Book. My use-case is that I should be able to add a new book to the database with an author that already exists in the database.

models.py

class Author(models.Model):    
    author_id = models.CharField(max_length=20, primary_key=True)
    name = models.CharField(blank=True, null=True)

    def __unicode__(self):
        return self.name

    class Meta:
        ordering = ('author_id',)

class Book(models.Model):    
    title = models.CharField(max_length=50, primary_key=True)
    authors = models.ManyToManyField(Author)

    def __unicode__(self):
        return self.title

    class Meta:
        ordering = ('title',)

serializers.py

class AuthorSerializer(serializers.ModelSerializer):
    class Meta:
        model = Author
        fields = ('author_id', 'name')


class BookSerializer(serializers.ModelSerializer):
    authors = AuthorSerializer(many=True)

    class Meta:
        model = Book
        fields = ('title', 'authors')

    def create(self, validated_data):
        book = Book.objects.create(name=validated_data['title'])

        for item in validated_data['authors']:
            author = Author.objects.get(author_id=item['author_id'])
            book.authors.add(author)

        return book

Let's say my Author table already has an Author:

1, George RR Martin

Now if I want to add a new book with an existing author, this is the request I send using httpie:

http -j POST http://localhost/books title="The Winds of Winter" authors:='[{"author_id":"1"}]'

and when I do, I get this error:

Output Error

{
    "authors": [
        {
            "author_id": [
                "This field must be unique."
            ]
        }
    ]
}

It seems like the AuthorSerializer is being called which checks the provided author_id against the ones in the database already and throws this error.

Any help on this would be appreciated.

Seenu S
  • 3,381
  • 6
  • 30
  • 45
Sandman
  • 5,432
  • 5
  • 20
  • 23

1 Answers1

0

Is there a specific reason you have to use a custom PK field?

Django automatically creates primary key fields for you. If you simply delete that field from your model and your serializer (and create/run a migration on your database), you won't have to specify the pk in your POST call from your frontend, and Django will create an AutoField that auto-increments your model's id:

class Author(models.Model):    
    # Remove this line and run makemigrations.
    # author_id = models.CharField(max_length=20, primary_key=True)
    name = models.CharField(blank=True, null=True)

    def __unicode__(self):
        return self.name

    class Meta:
        ordering = ('author_id',)

If not, consider using an models.AutoField rather than models.CharField for your primary key field, and again, don't include this in your POST call.

Note, that if you already have a big database created, you might have to do some intricate work in your migration, a la this answer:

Community
  • 1
  • 1
YPCrumble
  • 26,610
  • 23
  • 107
  • 172
  • How do I associate a new Book with an existing Author in that case in a POST request to create a new book? – Sandman Sep 15 '15 at 16:57
  • You would send the name of the Author in the POST request, and use something like `author, created = Author.objects.get_or_create(name=data['name'])` in your view. – YPCrumble Sep 15 '15 at 17:25