[Fixed]-Using Models in Django-Rest Framework

1👍

you don’t need to use models, but you really should. django’s ORM (the way it handles reading/writing to databases) functionality is fantastic and really useful.

if you’re executing raw sql statements all the time, you either have a highly specific case where django’s functions fail you, or you’re using django inefficiently and should rethink why you’re using django to begin with.

0👍

Django REST Framework is designed to work with Django Framework. And Django ORM is an integral part of Django Framework. Granted, that it is possible to use Django and DRF without using ORM, but you will be basically fighting against the framework instead of using the framework to help you. So, you have three basic approaches.

  1. If all you want is to develop RESTful APIs in python and pull data from an existing MySQL database or you don’t have a database, but you want something simple. You can use something framework agnostic, like restless (http://restless.readthedocs.io/en/latest/) or even hug (https://github.com/timothycrosley/hug)

  2. If you do not have any existing data and you want a full blown web framework, you should consider using Django (I make my living as a Django dev, there is no shame in this) and embrace the ORM. In this case, DRF is one of the better REST frameworks for Django at the moment.

  3. If you have existing database and are somehow stuck with using Django, there are some ways to use Django ORM with existing data, you should look at Django docs on the topic (https://docs.djangoproject.com/en/1.9/howto/legacy-databases/)

0👍

Why would you use Django without hitting the database with the ORM? Most of the times the ORM works as you’d expect, and even allow you to perform searches like this:

class Foo(models.Model):
    code = models.CharField(max_length=10, ...)

class Bar(models.Model):
    code = models.CharField(max_length=10, ...)
    foo = models.ForeignKey(Foo, ...)

And perform a query like this:

Bar.objects.get(code='baz', foo_code='bat')

Which would be the same, but better, than:

select bar.* from yourapp_bar bar inner join yourapp_foo foo on (bar.foo_id = foo.id) where bar.code = 'baz' and foo.code = 'bat'

Shorter and more maintainable.

Now, speaking about Django Rest Framework and Django in general: Although the latter modifications to both Django and DRF involve you cannot suddenly expect nested objects be created in the same moment the parent objects are (e.g. Foo is parent, while Bar is nested), as it happens in relation managers (Django) and create/update methods in the ModelSerializer class, you can still trust Django to save your time, effort, and life by using it instead of SQL.

I will give you an example with DRF. We will assume only Foo models are involved here. Which one would you prefer?

# yourapp.urls
from .views import UserViewSet
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register(r'users', UserViewSet)
urlpatterns = router.urls

# yourapp.views
class FooViewSet(viewsets.ModelViewSet):
    """
    A viewset that provides the standard actions for
      a single foo element
    """
    queryset = Foo.objects.all()
    serializer_class = FooSerializer
    # I am assuming you created the FooSerializer to map certain fields...

or …

# yourapp.urls
from .views import mywholeurl
from django.conf.urls import url

urlpatterns = [
    url('users/(\d+)', mywholeview),
]

# yourapp.views

from django.db import connection
from rest_framework import status
from rest_framework.response import Response

def mywholeview(request, id):
    cursor = connection.cursor()
    if request.method in ('POST', 'PUT'):
        cursor.execute('update yourapp_foo set %s where id = %%s' % ', '.join(["%s=%%s" % p[0] for p in request.data.items()]), list(p[1] for p in request.data.items()) + [id])
        row = cursor.fetchone()
        if row[0]
            return Response(status=status.HTTP_201_ACCEPTED)
        else:
            return Response(status=status.HTTP_404_NOT_FOUND)
    elif request.method = 'GET':
        cursor.execute('select * from yourapp_foo where id = %s', [id])
        row = cursor.fetchone()
        if row:
            columns = [col[0] for col in cursor.description]
            data = zip(columns, row)
            return Response(data, status=status.HTTP_200_OK)
        else:
            return Response(status=status.HTTP_404_NOT_FOUND)
    elif request.method = 'DELETE':
        cursor.execute('delete from yourapp_foo where id = %s', [id])
        row = cursor.fetchone()
        if not int(row[0]):
            return Response(status=status.HTTP_404_NOT_FOUND)
        else:
            return Response(status=status.HTTP_204_NO_CONTENT)

the latter code is untested and only serves for teoretical purpose. it is pretty insecure and not intended to be executed in production since it is a bad idea

I would prefer with the shortest approach.

My conclusion is: learn the ORM! If you need to respect your database because it is preexisting, you could use managed models. But always… use the ORM and the features given to you by both Django and DRF.

Leave a comment