djangoserializationdjango-rest-frameworkm2m

django restframework - Serializer for creating m2m relationship


I am using django-restframework for my API. I created a serializer which should list my objects and should be able to create them.

I have a Contact entity and Product. There is a standard m2m between it for the likes.

Here's my model:

class Contact(models.Model):
    ...
    products_of_interest = models.ManyToManyField(Product, related_name="interested_contacts")

My serializer is as simple as it gets:

class ContactSerializer(serializers.ModelSerializer):

    class Meta:
        model = Contact

When I list my contacts via this serializer I get all my contact objects with an array of product ids - awesome:

"products_of_interest": [
        1,
        2
    ]

Now, when I want to create a contacts and populate the m2m, I get the following (via my Chrome Postman and form-data):

I have some experience with serializers, so I thought, maybe I need to tell the serializer, that I want to give him more than one product. So I added this in my serializer:

products_of_interest = ProductSerializer(many=True, required=False, read_only=False)

Now I get this error:

"<Contact: >" needs to have a value for field "contact" before this many-to-many relationship can be used.

I'm totally lost now. What can I do? It can't be that I need to override standard rfw-functions for saving a damn easy m2m, can it?


Solution

  • What version of Django and drf are you using? I cannot reproduce your errors using Django 1.7 and drf 2.4.2. Here's my code:

    models.py

    from django.db import models
    
    class Product(models.Model):
        pass
    
    
    class Contact(models.Model):
        products_of_interest = models.ManyToManyField(Product,
            related_name="interested_contacts")
    

    serializers.py

    from .models import Contact
    from rest_framework import serializers
    
    
    class ContactSerializer(serializers.ModelSerializer):
        class Meta:
            model = Contact
    

    views.py

    from rest_framework import viewsets
    from .models import Contact
    from .serializers import ContactSerializer
    
    class ContactViewSet(viewsets.ModelViewSet):
        queryset = Contact.objects.all()
        serializer_class = ContactSerializer
    

    urls.py

    from django.conf.urls import include, url
    
    from rest_framework import routers
    from . import views
    
    router = routers.DefaultRouter()
    router.register(r'contacts', views.ContactViewSet, 'contacts')
    urlpatterns = router.urls
    
    urlpatterns = [
        url(r'^', include(router.urls)),
        url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
    ]
    
    ./manage.py shell
    >>> from m2m_test.models import Product
    >>> for i in range(3): Product.objects.create()
    ...
    <Product: Product object>
    <Product: Product object>
    <Product: Product object>
    >>>
    

    And then in the web frontend at http://localhost:8000/contacts/:

    POST with Raw Data form: { "products_of_interest": [1, 2, 3] }

    -> just works.