0

I am new to Django & DRF and I am trying to replace the default api view given from ModelViewSet (scr1,scr2,scr3) with custom HTML templates. Default view works just fine, i've tested with postman and it can do CRUD functions(at least it seems so), but I have no idea how to substitute the default views with custom html pages. I did follow DRF docs - it worked, also searcged solutions(this one was promising), but I simply can't adopt it my situation. Please help!

models.py:


from django.db import models

class Package(models.Model):

    prod_name = models.CharField(max_length=255, default=0)
    quantity = models.IntegerField(default=0)
    unit_price = models.IntegerField(default=0)

    def __str__(self):
        return self.prod_name


class Orders(models.Model):

    order_id = models.CharField(max_length=255, default=0)
    package = models.ManyToManyField(Package)
    is_cod = models.BooleanField(default=False)

    def __str__(self):
        return self.order_id

serializers.py:

from rest_framework import serializers
from .models import Package, Orders

class PackageSerializer(serializers.HyperlinkedModelSerializer):
    id = serializers.IntegerField()
    prod_name = serializers.CharField(max_length=255, default=0)
    quantity = serializers.IntegerField(default=0)
    unit_price = serializers.IntegerField(default=0)

    class Meta:
        model = Package
        fields = "__all__"


class OrderSerializer(serializers.HyperlinkedModelSerializer):
    package = PackageSerializer(many=True)

    def get_or_create_packages(self, packages):
        print("this is package in gocp:", packages)
        package_ids = []
        i = 0
        for package in packages:
            print("i=", i)
            i += 1
            package_instance, created = Package.objects.get_or_create(pk=package.get('id'), defaults=package)
            print("package id:", package.get('id'))
            package_ids.append(package_instance.pk)
            print("package_ids:",  package_ids)
        return package_ids

    def create_or_update_packages(self, packages):
        package_ids = []
        for package in packages:
            package_instance, created = Package.objects.update_or_create(pk=package.get('id'), defaults=package)
            package_ids.append(package_instance.pk)
        return package_ids

    def create(self, validated_data):
        print("this is validated_data:", validated_data)
        package = validated_data.pop('package', [])
        print("this is package:", package)
        order = Orders.objects.create(**validated_data)
        order.package.set(self.get_or_create_packages(package))
        return order

    def update(self, instance, validated_data):
        package = validated_data.pop('package', [])
        instance.package.set(self.create_or_update_packages(package))
        fields = ['order_id', 'is_cod']
        for field in fields:
            try:
                setattr(instance, field, validated_data[field])
            except KeyError:  # validated_data may not contain all fields during HTTP PATCH
                pass
        instance.save()
        return instance

    class Meta:
        model = Orders
        fields = "__all__"

views.py:

from .serializers import OrderSerializer, PackageSerializer
from .models import Package, Orders
from rest_framework import viewsets

class OrderViewSet(viewsets.ModelViewSet):
    serializer_class = OrderSerializer
    queryset = Orders.objects.all()


class PackageViewSet(viewsets.ModelViewSet):
    serializer_class = PackageSerializer
    queryset = Package.objects.all()

urls.py:

from django.urls import path, include


router = DefaultRouter()
router.register(r'order', OrderViewSet, basename='orders')
router.register(r'package', PackageViewSet, basename='package')


urlpatterns = [
                  path('api/', include(router.urls)),
              ]

I am assuming that:

  1. list(), create()/update() needs to be modified in views.py (class OrderViewSet & PackageViewSet), but how? I did try many different options to define - list(), create()/update() functions, but nothing worked, for example(in this particular case im not allowed to overide existing list method):
@action (renderer_classes=[TemplateHTMLRenderer], detail=True)
def list(self, request, *args, **kwargs):
    template_name = 'order_list.html'
    queryset = self.filter_queryset(self.get_queryset())
    serializer = self.get_serializer(queryset, many=True)
    return Response(serializer.data, template_name='order_list.html')

  1. Actual html templates need to conform to the nested model that I have and I am not sure how it would work with nested data. Since I can't solve the 1st point, can't test out and try to solve the 2nd point.

Will rendering_form serializer work? Taking the DRF docx exaple from work?:

{% load rest_framework %}

<html><body>

<h1>Orders - {{ orders.order_id }}</h1>

<form action="{% url 'order-detail' pk=orders.pk %}" method="POST">
    {% csrf_token %}
    {% render_form serializer %}
    <input type="submit" value="Save">
</form>

</body></html>

Perhaps I should forget ModelsViewSet and go with APIView?(though in this particular case if there exist a solution I would prefer to know it).

Alex
  • 1
  • 2

0 Answers0