0

I am new to django and faced to several problems trying to write a simple service.

  1. What am I trying to do?

    I intend to write a generic crud service for my models using rest-framework library.
    I don't want to write serializers and views to all my models and trying to optimize code and learn some useful stuff.

  2. My model

    Let's imagine I have an abstract BaseBusinessObject

    class BaseBusinessObject(models.Model):
    
        CreatedAt = models.DateField()
        UpdatedAt = models.DateField()
    
        class Meta:
            abstract = True
    
    

    I also have a plenty of concrete classes, which are inherited from base one:

    class Product(BaseBusinessObject):
         Description: models.TextField()
         Type: models.CharField()
    
    ....
    
    class Company(BaseBusinessObject):
        Title: models.CharField()
    
    ....
    
    class Person(BaseBusinessObject):
        Name: models.CharField()
    

    and so on

  3. What I want

    I already figured out, that with rest-framework I can create serializers and views, then register router for url .../Product, .../Company, .../Person. But what if I have 1000 classes? This is boring

    A. How can I dynamically specified url's for child objects? I don't want to hardcode methods, I am looking for solution...something like this: .../api/Entities/ClassName

    B. How can I then use my dynamically created urls in django-rest-framework?

    router.register('persons', PersonViewSet)
    

    How can write it in more generic way?

    router.register('<ClassName>', <GenericViewSet>)
    

    C. Using DRF I can create my viewset for each concrete class in my model:

    class PersonViewSet(viewsets.ModelViewSet):
    queryset = Person.objects.all()
    serializer_class = PersonSerializer
    

But as I said I have a lot of classes. How can I write it in more generic way?

I tried to create a view set for abstract class, but there are some trouble when querying an abstract object.

Is it possible to create such service for an abstract class and then all its child simply(or not simply) inherit CRUD methods?

Maybe I should try to write a factory for serializers and viewsets?

What possible solutions could I implement for solving my problem?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Valeriy
  • 83
  • 1
  • 8
  • @Valerity Checkout this website it may help you https://learnbatta.com/course/django-rest-framework/ – anjaneyulubatta505 Jul 18 '19 at 10:40
  • thanks, but it does not fit enought. I have already read actual docs about DRF. The question is how can I use it for abstract model and then for all child classes OR there are another possible solution. – Valeriy Jul 18 '19 at 11:54
  • need more information with expected input and output – anjaneyulubatta505 Jul 18 '19 at 12:03
  • I can't tell u precisely what I expected because I am really new at Django. But I want to write a service for CRUD operations for my business objects. Let's imagine they are inherited from abstract class. How should I do it in generic way? I tried to explain it in my question. I am not a native english-speaker. Am I explain myself in a clear way? – Valeriy Jul 18 '19 at 12:33

2 Answers2

2

After 2 days of walking around I finally find my solution. May be someone else will face the some problem, so I trying to explain what I had already done.

First, I create a "base" application inside my django project and add it to settings.py. Then I create an abstract class in models.py:

class BaseCrudEntity(models.Model):
    pass
    class Meta:
        abstract = True

I want to write a generic service for CRUD operations for all "business" classes. The problem is that I don't want to write serializers and views for them - I want to create them "on fly", dynamically. I decided to use django rest framework as well, because I am not intended to create a bycicle again. I decided to inherit all my "business" classes from that abstract one and write a service for all possible "families"

So I have to create a fabric which is responsible for VeiwSet creation. Here is my view.py:

class BaseCrudViewSetFabric():

    @classmethod
    def CreateViewSet(self, _context):
        classname = _context.__name__ + 'ViewSet'
        return type(classname, (viewsets.ModelViewSet,), {
            'queryset':_context.objects.all(),
            'serializer_class':BaseCrudSerializerFabric.CreateSrializer(_context)
        })
        pass

here _context - variable which describes concrete class of my model. as you can see this function creates a concrete ViewSet based on my context. Inside it a Serializers fabric is called. Here the code of my serializers.py:

class BaseCrudSerializerFabric():

    @classmethod
    def CreateSrializer(self, _context):
        classname = _context.__name__
        _Meta = type('Meta', (), {'model':_context,'fields':'__all__'})
        _crudserializer = type(
            classname,
            (serializers.ModelSerializer,),
            {'Meta': _Meta}        
        )
        return _crudserializer

Moreover, I have to write a service for dynamically routing - I don't wanna hardcode my urls. Here the example ursl.py from core project:

from base.urls import router
url(r'^api/v1/', include(router.urls))

and from base/urls.py:

from rest_framework.routers import DefaultRouter, SimpleRouter
from base.models.BaseCrudEntity import BaseCrudEntity
from base.views.basecrud_view import BaseCrudViewSetFabric

class CustomRouter(SimpleRouter):

    def RoutRegister(self):
        childs = getChilds(BaseCrudEntity)
        #print(childs)
        for ch in childs:
            if (ch._meta.abstract == False):
                #print(ch.__name__)
                prefix = ch.__name__
                self.register(prefix, BaseCrudViewSetFabric.CreateViewSet(ch))
        return(self)
    pass

router = CustomRouter()
router.RoutRegister()

Finally I simply create some concrete models:

from django.db import models
from base.models.BaseCrudEntity import BaseCrudEntity

class Person(BaseCrudEntity):

    Name = models.CharField(max_length = 255)
    Surname = models.CharField(max_length = 255)
    Patronymic = models.CharField(max_length = 255, null = True)
    DateOfBirth = models.DateField(null = True)
    #slug = models.SlugField(default = 'hui', editable = False)

    def __str__(self):
        return "{} {} {}".format (self.Surname, self.Name, self.Patronymic)

and thats all. When application starts it register a route for http://127.0.0.1:8000/api/v1/Person and creates serializers and viewsets so all CRUD operations provided by Django- Rest Framework will be provided as well.

Valeriy
  • 83
  • 1
  • 8
0

I would suggest using query parameters instead of path parameters, then you just register one URL and process the various elements of the request and route it correctly server-side. When do I use path params vs. query params in a RESTful API?

  • I thought about that, but this is so boring if u have a plenty of classes with similar methods. I already done **A** - about dynamic URL's: 1. I decided to create a BaseCrudEntity for all such classes and inherit it 2. I define a function that returns a set of child classes 3. THen I wroute a CustomRouter and register all routes with `self.register(prefix, GenericViewSet)` As a result I have a plenty of URL's like ...Entity/ – Valeriy Jul 18 '19 at 22:56