2
\$\begingroup\$

A working example of mine, trying to streamlining my Django views, with absolute inspiration from Laravel:

class BaseController(View):
    template_404 = "404.html"

    def __call__(self, *args, **kwargs):
        return self.view(*args, **kwargs)

    def view(self, request, slug=None):
        method = request.method.lower()
        if hasattr(self, method):
            return getattr(self, method)(request, slug)
        return self.forbidden(request)

    def get(self, request, slug):
        if slug is not None:
            return getattr(self, "show")(request, slug) if hasattr(self, "index") else self.forbidden(request)
        return getattr(self, "index")(request) if hasattr(self, "index") else self.forbidden(request)

    def post(self, request, slug):
        return getattr(self, "store")(request) if hasattr(self, "store") else self.forbidden(request)

    @staticmethod
    def forbidden(request):
        return HttpResponseForbidden("Method not allowed")

    def page_not_found(self, request):
        return render(request, self.template_404)

Inherited by:

class EulerController(BaseController):
    template_name_index = "euler_index.html"
    template_name_show = "euler_show.html"

    def index(self, request):
        euler_posts = EulerPost.objects.all()
        return render(request, self.template_name_index, {"euler_posts": euler_posts})

    def show(self, request, slug):
        euler_post = EulerPost.objects.filter(slug=slug).first()
        return render(request, self.template_name_show, {"euler_post": euler_post})

and called by:

urlpatterns = [
    url(r'^$', EulerController(), name='main'),
    url(r'^(?P<slug>[\w-]+)/$', EulerController(), name='resource'),
]

and the mock model:

class EulerPost(model):
    slug = models.CharField(default=None, max_length=200, blank=False, unique=True)

I left Django for PHP-Laravel, long ago believing myself to be an to unstructured for the freedom of Django. But now I feel I am on the right track.

\$\endgroup\$
2
\$\begingroup\$

It is usually better to ask forgiveness than permission and explicit is better than implicit. So I would change your getattr..if hasattr to a try..except, which is a lot easier to understand:

def post(self, request, slug):
    try:
        return self.store(request)
    except AttributeError:
        raise HttpResponseForbidden("Method not allowed")

And similar for get and view:

def get(self, request, slug):
    try:
        if slug is not None:
            return self.show(request, slug)
        return self.index(request)
    except AttributeError:
        raise HttpResponseForbidden("Method not allowed")

def view(self, request, slug=None):
    try:
        return getattr(self, request.method.lower())(request, slug)
    except AttributeError:
        raise HttpResponseForbidden("Method not allowed")
\$\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.