Search code examples
djangodjango-modelsmany-to-manydjango-rest-framework

many_init takes exactly 1 argument (3 given) django rest framework


so I have slightly complex database structure with quite a few m2m relations. I am facing this issue with some of the viewsets that are defined on a few tables structured quite similarly. Following are some example models.

# Boards model
class Board(models.Model):
    id = models.CharField(max_length=10, primary_key=True)
    board = models.CharField(max_length=40, unique=True)

    class Meta:
        verbose_name_plural = 'Boards'

    def __unicode__(self):
        return self.board


# Grades model
class Grade(models.Model):
    id = models.CharField(max_length=10, primary_key=True)
    grade = models.CharField(max_length=40, unique=True)

    class Meta:
        verbose_name_plural = 'Grades'

    def __unicode__(self):
        return self.grade


# BoardGrades model
class BoardGrade(models.Model):
    board = models.ForeignKey(to=Board)
    grade = models.ForeignKey(to=Grade)

    class Meta:
        verbose_name_plural = 'BoardGrades'
        unique_together = ('board', 'grade')

    def __unicode__(self):
        return '%s - %s' % (self.board.board, self.grade.grade)

# Subjects model
class Subject(models.Model):
    id = models.CharField(max_length=5, primary_key=True)
    name = models.CharField(max_length=40, unique=True, blank=False, null=False)
    board_grade = models.ManyToManyField(to='lguser.BoardGrade')
    def_icon = models.ImageField(upload_to='subject_icons', null=True, blank=True)
    sel_icon = models.ImageField(upload_to='subject_icons', null=True, blank=True)

    class Meta:
        verbose_name_plural = 'Subjects'

    def __unicode__(self):
        return self.name


# Units model
class Unit(models.Model):
    name = models.CharField(max_length=100, unique=True, blank=False, null=False)
    subject = models.ForeignKey(to=Subject, blank=False, null=False, related_name='units')
    board_grade = models.ManyToManyField(to='lguser.BoardGrade')
    icon = models.ImageField(upload_to='unit_icons', null=True, blank=True)

    class Meta:
        verbose_name_plural = 'Units'

    def __unicode__(self):
        return '%s - %s' % (self.subject.name, self.name)

Following are the serializer classes I wrote for the the Subject and Unit model

class SubjectSerializer(serializers.HyperlinkedModelSerializer):
    board_grade = serializers.PrimaryKeyRelatedField(queryset=BoardGrade.objects.all(), many=True)

    class Meta:
        model = Subject
        fields = ('name', 'board_grade', 'def_icon', 'sel_icon', 'id', 'url')


class UnitSerializer(serializers.PrimaryKeyRelatedField):
    board_grade = serializers.PrimaryKeyRelatedField(queryset=BoardGrade.objects.all(), many=True)
    subject = serializers.PrimaryKeyRelatedField(queryset=Subject.objects.all())

    class Meta:
        model = Unit
        fields = ('name', 'subject', 'board_grade', 'icon', 'id', 'url')

And following are the viewsets defined for the above two serializers

class SubjectViewSet(viewsets.ModelViewSet):
    authentication_classes = [JSONWebTokenAuthentication, SessionAuthentication, BasicAuthentication]
    permission_classes = [permissions.IsAuthenticated, permissions.IsAdminUser]
    queryset = Subject.objects.all()
    serializer_class = SubjectSerializer


class UnitViewSet(viewsets.ModelViewSet):
    authentication_classes = [JSONWebTokenAuthentication, SessionAuthentication, BasicAuthentication]
    permission_classes = [permissions.IsAuthenticated, permissions.IsAdminUser]
    queryset = Unit.objects.all()
    serializer_class = UnitSerializer

and finally the urls:

router = DefaultRouter()
router.register(r'subject', SubjectViewSet)
router.register(r'unit', UnitViewSet)
urlpatterns = router.urls

when I hit the /subject/ url with a GET requests it gives me the JSON array as desired. but when I hit the /unit/ url with the request it throws an error as follows.

TypeError at /lgadmin/unit/
__init__() takes exactly 1 argument (3 given)
Request Method: GET
Request URL:    http://127.0.0.1:8000/lgadmin/unit/
Django Version: 1.8.4
Exception Type: TypeError
Exception Value:    
 __init__() takes exactly 1 argument (3 given)

I am unable to see where the issue is. I used the prebuilt ModelViewSet in as vanilla a fashion as I could. Any help??


Solution

  • Looking in your code class UnitSerializer(serializers.PrimaryKeyRelatedField): that is invalid.

    Going by the docs there you would have to use one of the following -

    serializers.ModelSerializer
    serializers.HyperlinkedModelSerializer
    serializers.ListSerializer
    serializers.BaseSerializer
    

    You're trying to pass a field serializer into a serializer "view".