0

I am new to Django rest framework, I am used to develop APIs in .net I want to to create 2 APIs one get which gets the Article and Image related to it by pk id, and one post which adds article and photo, I have tried different methods but couldn't get what I want, if anyone can help or share some site where I can learn such thing, that would be great, Thanks in advance PS: select_related is only giving me id of article model.

These are my 2 models:

from django.db import models


class Article(models.Model):
    Heading = models.CharField(max_length=200, null=True)
    Article = models.TextField(null=True)
    CreatedBy = models.IntegerField(null=True)
    CreatedDate = models.DateTimeField(null=True)
    IsDeleted = models.BooleanField(default=False)


class ArticleImage(models.Model):
    Image = models.ImageField(upload_to='photos/', null=True)
    ImageArticle = models.ForeignKey(Article, on_delete=models.CASCADE)

and these are my serializers:

from rest_framework import serializers
from .models import Article, ArticleImage


class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = ('id', 'Heading', 'Article')


class ArticleImageSerializer(serializers.ModelSerializer):
    class Meta:
        model = ArticleImage
        fields = ('id', 'Image', 'ImageArticle')

and these are my views:

from django.shortcuts import render
from django.views import View
from rest_framework import views
from rest_framework import viewsets
from .models import Article, ArticleImage
from .serializers import ArticleSerializer, ArticleImageSerializer
from itertools import chain
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.http import Http404


class ArticleView(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer


class ArticleImageView(viewsets.ModelViewSet):
    queryset = ArticleImage.objects.all()
    serializer_class = ArticleImageSerializer


class ArticleWImage(viewsets.ModelViewSet):
    queryset = ArticleImage.objects.all().select_related()
    serializer_class = ArticleImageSerializer


class ImageWArticle(viewsets.ModelViewSet):
    queryset = Article.objects.select_related()
    serializer_class = ArticleSerializer


class ArticleList(APIView):
    def get(self, request):
        article = Article.objects.all()
        article_image = ArticleImage.objects.all()
        return render(request, {
            'article': article,
            'articleImage': article_image
        })

URLs:

from django.urls import path, include
from . import views
from rest_framework import routers

router = routers.DefaultRouter()
router.register('articles', views.ArticleView)
router.register('articleImage', views.ArticleImageView)
router.register('articleWithImage', views.ArticleWImage)
router.register('imageWithArticle', views.ImageWArticle)


urlpatterns = [
    path('', include(router.urls)),
    path('articleImageGet/', views.ArticleList.as_view())
]

3 Answers3

0

You can use the generic views that come bundled with Drango Rest Framework.

For you use case where you want only GET and POST I think CreateAPIView [for POST], RetrieveAPIView [for GET] will be enough.

http://www.django-rest-framework.org/api-guide/generic-views/#createapiview

http://www.django-rest-framework.org/api-guide/generic-views/#retrieveapiview

Something like this:

path('articles/', views.ArticleListCreateAPIView.as_view())

class ArticleListCreateAPIView(CreateAPIView, RetrieveAPIView):
    model = Article
    serializer_class = ArticleSerializer


class ArticleSerializer(serializers.ModelSerializer):
    images = serializers.SerializerMethodField()
    class Meta:
        model = Article
        fields = ('id', 'Heading', 'Article', 'images')

    def get_images(self, article):
        images = ArticleImage.objects.filter(article=article)
        return ArticleImageSerializer(data=images, many=True).data


class ArticleImageSerializer(serializers.ModelSerializer):
    class Meta:
        model = ArticleImage
        fields = ('id', 'Image', 'ImageArticle')
Umair Mohammad
  • 4,489
  • 2
  • 20
  • 34
  • Can I use 2 models referenced with foreign key in the generic views? – Ayush Bhargava Jul 05 '18 at 09:12
  • my seperate get put post delete api are working fine, I need something which can return and add both the models at the same time – Ayush Bhargava Jul 05 '18 at 09:14
  • Aha you're asking about creating nested objects ? You want images also be created , right ? – Umair Mohammad Jul 05 '18 at 09:19
  • yes may be, sorry I didn't understant, I want something like this as a result of a get request { "id": 2, "Image": "http://127.0.0.1:8000/media/photos/2018/07/01/Sebastian_Rottmair.jpg", "article" : { "id": 1, "Heading": "Sample", "Article": "This is a sample article" } } – Ayush Bhargava Jul 05 '18 at 09:24
  • and I should be able to Post image as well as whole article including heading and article text in one api – Ayush Bhargava Jul 05 '18 at 09:25
  • I think it's doable with nested serializer and to create/update nested objects we need to override the update method of serializer as DRF doesn't support updating the nested object, as of now. Overriding the create/update method of serializer should bring you on path to resolve this – Umair Mohammad Jul 05 '18 at 09:28
  • https://stackoverflow.com/questions/41312558/django-rest-framework-post-nested-objects – Umair Mohammad Jul 05 '18 at 09:33
0

According to the official DRF docs (which is pretty good) you can try something like this:

class FooList(APIView):
    def get(self, request, format=None):
        Foos = Foo.objects.all()
        serializer = FooSerializer(Foos, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer = FooSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Then you have to properly register your viewset as view in urls.py:

urlpatterns = [
    url(r'^foos/$', views.FooList.as_view()),
]
sur0k
  • 334
  • 1
  • 6
0

You can always overwrite the natural functionality of viewset. Best way to learn how to overwrite go through DRF codebase.

say for example generally "/articles" will provide list of articles and "/articles/pk" will provide article information of the that primary_key article. If you want ot overwrite its functionality you can something like this ... from django.shortcuts import get_object_or_404 from rest_framework.response import Response from .models import Article, ArticleImage from .serializers import ArticleSerializer, ArticleImageSerializer

class ArticleViewSet(viewsets.ViewSet):
    """
    A simple ViewSet for listing or retrieving articles.
    """


    def retrieve(self, request, pk=None):
        queryset = Article.objects.all()
        article_instance = get_object_or_404(queryset, pk=pk)
        article_serializer = ArticleSerializer(article_instance)
        image_instance = ArticleImage.objects.get(ImageArticle=article_instance.id)

        return Response({
                'article': article_serializer.data, 
                 'image': image_instance.image
               })

if you want to know more how it works read this

Shakil
  • 4,520
  • 3
  • 26
  • 36