3
\$\begingroup\$

The repetition is super obvious here. How can I rewrite this code? I need one base method in which I pass a Django model, to call objects.filter, but I can't figure out how to do it.

from profiles.models import BasicInfo, BillingInfo, DocumentInfo

__author__ = 'vol'


class BasicInfoService:
    def __init__(self):
        pass

    @staticmethod
    def get_by_profile_id(profile_id, is_versioned):
        if is_versioned:
            return BasicInfo.objects.filter(profile_id=profile_id).order_by('-version')
        return BasicInfo.objects.filter(profile_id=profile_id).order_by('-version')[:1][0]


class BillingInfoService:
    def __init__(self):
        pass

    @staticmethod
    def get_by_profile_id(profile_id, is_versioned):
        if is_versioned:
            return BillingInfo.objects.filter(profile_id=profile_id).order_by('-version')
        return BillingInfo.objects.filter(profile_id=profile_id).order_by('-version')[:1][0]


class DocumentInfoService:
    def __init__(self):
        pass

    @staticmethod
    def get_by_profile_id(profile_id, is_versioned):
        if is_versioned:
            return DocumentInfo.objects.filter(profile_id=profile_id).order_by('-version')
        return DocumentInfo.objects.filter(profile_id=profile_id).order_by('-version')[:1][0]
\$\endgroup\$
2
\$\begingroup\$

The template method pattern seems useful here:

  • Create a base class with a get_by_profile_id method that calls a get_queryset method to get the at appropriate QuerySet object to work with
  • The base class doesn't implement get_queryset, it's the job of the subclasses. This is the template method

Something along the lines of this in the base class:

def get_by_profile_id(self, profile_id, is_versioned):
    queryset = self.get_queryset().filter(profile_id=profile_id).order_by('-version')
    if is_versioned:
        return queryset
    return queryset[:1][0]

And in the subclass for BasicInfo:

def get_queryset(self):
    return BasicInfo.objects

Notice that I eliminated another duplication in the following and ordering logic. Note that Djangi will not execute the query until elements are accessed in the query set, so when I initialize queryset before the if condition, that doesn't hit the database.

\$\endgroup\$
2
  • \$\begingroup\$ Can you check out my answer, and write some comment to that? I used your idea with get_queryset function. \$\endgroup\$
    – Valery
    Jun 18 '15 at 5:07
  • \$\begingroup\$ Yeah like that. I improved it a tiny bit, hope you like it (see the edit on your answer) \$\endgroup\$
    – janos
    Jun 18 '15 at 5:13
0
\$\begingroup\$

Using the @janos idea, I try to apply inheritance for my implementation, it looks pretty compact right know:

from profiles.models import BasicInfo, BillingInfo, DocumentInfo

__author__ = 'vol'

class ProfileInfoService:
    def __init__(self, provider):
        self.info_provider = provider

    def get_by_profile_id(self, profile_id, is_versioned):
        info = self.info_provider.filter(profile_id=profile_id).order_by('-version')
        if is_versioned:
            return info
        if info:
            return info[:1][0]          
        return []          


class BasicInfoService(ProfileInfoService):
    def __init__(self):
        ProfileInfoService.__init__(self, BasicInfo.objects)


class BillingInfoService(ProfileInfoService):
    def __init__(self):
        ProfileInfoService.__init__(self, BillingInfo.objects)


class DocumentInfoService(ProfileInfoService):
    def __init__(self):
        ProfileInfoService.__init__(self, DocumentInfo.objects)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.