[PYTHON] About Django's ProxyModel

Django has a ProxyModel. How is this convenient to use and when is it useful?

Proxy model https://docs.djangoproject.com/en/3.0/topics/db/models/#proxy-models

This is just the explanation.

You may want to change only the behavior of Python in your model. We may change the default manager or add new methods.

However, it seems that there are various itchiness, and I am worried about how to use it conveniently. It's just a purposeful means, so I don't want to force it. Right way to return proxy model instance from a base model instance in Django?

For the time being, what about this situation?

Django is a structure that allows you to have multiple applications in your project. A common pattern is to use Django to create an admin screen (a admin tool for people inside, not Django Admin), or DRF to create an API? In such a case, you will often want to use the DB in common for these two apps. For example, large-scale services are converted to microservices, and it may not be divided (managed) in that way, but I think that there are quite a lot of such configurations in startups that want results first and foremost.

スクリーンショット 2020-02-20 16.33.53.png

When taking such a configuration, it is necessary to use a common model in Django and DRF, but this can be found quite easily by searching, and the system is completed and implemented basically nothing. There is no problem.

Do you write a lot of methods in model?

Django's ORM is excellent and I rarely have the opportunity to write raw SQL, but I don't think it's okay to write ORM instructions in the view. It's like this.

class MyViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    queryset = schema.MyObject.objects.all().order_by('id')
    serializer_class = MyObjectSerializer

What's the difference between this and the old-fashioned do not write SQL in Controller? Do you know that it's no good if you make it like this?

class MyViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    queryset = schema.MyObject.objects.filter(type=schema.MyObject.TYPE.OPEN).order_by('id')
    serializer_class = MyObjectSerializer

So, I think it's better to write a method in model.

class MyViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    queryset = schema.MyObject.filter_of_open_object()
    serializer_class = MyObjectSerializer

class MyObject(models.Model):
    @classmethod
    def filter_of_open_object(cls):
        return cls..objects.filter(type=schema.MyObject.TYPE.OPEN).order_by('id')

Like this.

How about writing a model that uses methods that are not related to other apps in common? ??

For example, the LIST-type QUERY that lists even the logically deleted data required for the Admin application is not required on the API side. If you hit it by mistake rather than unnecessary (it's an implementation mistake), you'll end up with data that you shouldn't show.

__ ProxyModel can be used in such cases. __

It's like this. スクリーンショット 2020-02-20 16.45.12.png

Notes on Model method and ProxyModel

Example of how to write ProxyModel

class Article(XModel):
    TYPE = Choices(
        ('DRAFT',   'draft'),
        ('PUBLISH', 'Now open'),
    )

    type = StatusField(
        choices_name='TYPE',
        blank=False,
        default=TYPE.DRAFT,
        help_text="Article status",
    )

    text = models.TextField(
        null=False,
        blank=False,
        default="",
        help_text="Article content",
    )

    writer = models.ForeignKey(
        to="Account",
        related_name="articles",
        null=False,
        on_delete=models.DO_NOTHING,
        help_text="Article writer",
    )

class ArticleProxy(ProxyModel, schema.Article):

    @classmethod
    def list_of_draft(cls):
        return cls.objects.filter(type=cls.TYPE.DRAFT)

Please write in this form. The point is cls.objects.filter. Even if the meaning is the same, if it is schema.Article.objects.filter, the return value will be an array of ʻArticle` (strictly speaking, it is a QuerySet, not an array).

Notes on writing methods in Model (Proxy)

class ArticleProxy(ProxyModel, schema.Article):

    @classmethod
    def list_of_future(cls):
        return cls.objects.filter(resavation_at=now())


class MyViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    queryset = ArticleProxy.list_of_future()
    serializer_class = ArticleSerializer

Do you know this is a bug? now () is evaluated only once and is not calculated every time there is a request. The essence of this problem is that methods (or functions in the old way) are essentially black boxes and should be called without knowing their contents. In this example, the View implementer usually says "__ There is a convenient method, let's use it! __".

Why do you stick to this?

There is an idea (in me) that even communication is useless in startups that start up businesses at explosive speed. I feel that it is an era when 1on1 is recommended and management is emphasized while changing from spinach to zassou, but at XTech, the organizations that need management are old, each is not a professional, so that's what it is. I think I need. (The longest part of my career is management, but w)

In short, I think that a framework that can be understood without communication even when implementing it, and that if you make it normally, you will not create strange bugs or security holes is important for increasing productivity.

Recommendation of Proxy Model

The person who implements each application adds a method on ProxyModel and uses it. You cannot access data that only the administrator can access if you use it normally (unless you write such a method)

Finally

There is also a workaround in the case where you write a method in the Model given in the above example and it is used like a black box to step on a bug. I'm wondering if you can imagine this or put it in the next content.

Since it is a scribble, I think there are typographical errors and strange parts, so if you can comment, I will make time to review it!

Recommended Posts

About Django's ProxyModel
Beginner notes about django's setting.py
About Django's deconstruct and deconstructible
About LangID
About CAGR
About python-apt
About Permission
About requirements.txt
About locale
About permissions
About Opencv ②
About axis = 0, axis = 1
About Opencv ③
About import
About numpy
About pip
About Linux
About endian
About Linux
About import
About Opencv ①
Django's ImageField
About Linux
About Linux
About Linux ①
About cv2.imread
About _ and __
About wxPython
About Django's Model.save () behavior and MySQL deadlock error
Talking about array parameter transfer to django's QueryDict