Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

Python Django REST Framework Security and Customization Customizing Serialization

How to represent Complex relationships using DRF

Apologies if this seems trivial but i want to know what is the most Django way to do this. Below are the models, views and serializers listed for reference.

There are 3 models. I am just showing the relevant fields for each, though they have multiple fields. Now, one blog can have multiple authors contribute to it. Similarly one author or contributor can contribute to multiple blogs.

class Blog(models.Model):
    title = models.CharField(max_length="120")
    ...

class Author(models.Model):
    title = models.CharField(max_length="120")
    ...

class BlogAuthor(models.Model):
    blog = models.ForeignKey('Blog') 
    author = models.ForeignKey('Author')
    creator = models.ForeignKey('auth.User')
    # Should the above relations be a Foreign Key or ManyToMany Field

I am using DRF 3.0 to create the below APIs:

    GET /blogs/1/author : to get a list of authors for the blog identified by id 1
    POST /blogs/1/author: create which authors are related to the blog 1
    GET /blogs/1/author/1: show details of the author 1 in context of the blog 1; for ex, author 1 may have contributed 300 words to blog 1 so this would return that along with some other details, say name of the author, picture of the author etc
    DELETE /blogs/1/author/1 : deletes the relation between blog 1 and author 1, thought both entities exist; just the relationship between them is deleted

The relevant urls:

path('blogs/<int:pk>/authors/', views.BlogAuthorList.as_view(), name='blogauthor-list'),
path('blogs/<int:pk>/authors/<int:pk>', views.BlogAuthorList.as_view(), name='blogauthor-detail'),

However i think i am getting an error because of this as 2 pks in the url. Should it be fk? How does it map to the relevant model ? Error:sre_constants.error: redefinition of group name 'pk' as group 2; was group 1 at position 39

I have also created the views and the serializers but i am not very sure.

Serializer:
class BlogAuthor(serializers.ModelSerializer):
        creator = serializers.ReadOnlyField(source='creator.username')

        class Meta:
            model = BlogAuthor
            fields = ('id', 'blog', 'author', 'creator')

    View:
    class BlogAuthorList(generics.ListCreateAPIView):
        queryset = BlogAuthor.objects.all() # notsure
        serializer_class = BlogAuthorSerializer
        permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

        #The below was working early but since i introduced the new URLs, see paths above am getting error as shown above
        def create(self, request, *args, **kwargs):
            public_personas = request.data.get('authors')
    #To handle multiple authors sent from API, ie, to handle requests such as #: 
   # {
   #     "blog": 1,
   #     "author": [1,3]
   # }
            data = {}
            response_data = []
            response_dict = {}
            for author in authors:
                data['blog'] = request.data.get('blog')
                data['author'] = author
                serializer = self.get_serializer(data=data)
                if serializer.is_valid():
                    self.perform_create(serializer)
                    headers = self.get_success_headers(serializer.data)
                    response_data.append(serializer.data)
                else:
                    return Response(data=serializer.errors, status=status.HTTP_400_BAD_REQUEST)
            response_dict['data'] = response_data
            return Response(response_dict, status=status.HTTP_201_CREATED, headers=headers)

        def perform_create(self, serializer):
            serializer.save(creator=self.request.user)

        # def list(self, request):
        #   Not Sure How To Do This


    #Not sure about this.
    class BlogAuthor(generics.RetrieveDestroyAPIView):
        ???

Thats quite a long question. Sorry about that. Do let me know your thoughts and point me in the right direction on how to do this. I feel this is quite a common occurence so should be straight forward but have scratched my head for quite some time now.