Django (3)


Django Rest Framework auto assign current user on creation

If you use the ModelViewSet provided by Django Rest Framework you overwrite the perform_create method on the ModelViewSet to auto set the current user to the model before saving.

class PostViewSet(viewsets.ModelViewSet):
  queryset         = Post.objects.all()
  serializer_class = serializers.PostSerializer

  def perform_create(self, serializer):
    kwargs = {
      'user': self.request.user # Change 'user' to you model user field.
    }

    serializer.save(**kwargs)

As usual my recommendation is to create “Mixin” like this one:

class UserCreateMixin(object):
  """
  By default the user field is "user" you can change it
  to your model "user" field.

  Usage:
  class PostViewSet(UserCreateMixin, viewsets.ModelViewSet):
    # ViewsSet required info...
    user_field = 'creator'
  """
  user_field = 'user'

  def get_user_field(self):
    """
    You can dynamically change the user field
    """
    return self.user_field

  def perform_create(self, serializer):
    kwargs = {
      self.get_user_field(): self.request.user
    }

    serializer.save(**kwargs)

If you think that there is a better way, let us know in the comments bellow.




Upload files to Django Rest Framework using AngularJS

Encoding the image to “base64”, send it to our DRF endpoint and on our DRF serializers change the ImageField to Base64ImageField was the implementation I used:

On the client side, on my angular app:

angular.controller('ImageUploadFormCtrl', function($scope, Photo){
  $scope.submitForm = function(isValid){
    if(isValid){
      f = new FileReader(); // or $window.FileReader()
      
      f.onload = function () {
        $scope.formData.image = f.result; // This is a base64 string

        Photo.save({}, $scope.formData).$promise.then(function(data){
          // 200 Response
          alert('Client image successfully updated.');
        }, function(error){
          // 400 Response
          console.log('Error', error);
          alert('An error has ocurred.');
        })
      };      
      
      // Read the file selected on the field with ID "image-field"
      f.readAsDataURL(document.getElementById('image-field').files[0]);
    }
  }
});

On the server side on my Django app, specifically on the serializers.py file:

import base64, uuid
from django.core.files.base import ContentFile

class Base64ImageField(serializers.ImageField):
  def to_internal_value(self, data):
    if isinstance(data, basestring) and data.startswith('data:'): # You can change "data:" to "data/image:"
      format, imgstr = data.split(';base64,')
      ext  = format.split('/')[-1]
      id   = uuid.uuid4()
      data = ContentFile(base64.b64decode(imgstr), name=id.urn[9:])

    return super(Base64ImageField, self).to_internal_value(data)

class PhotoSerializer(serializers.ModelSerializer):
  image = Base64ImageField(allow_empty_file=False)
  
  class Meta:
    fields           = ('id', 'image')
    model            = Photo
    read_only_fields = ('id', )

I found out that this is the cleaner way to do this. If you have another alternative, please share it.




Scaling Django Properly

I’m in love with Django and as a love we should be able to know how to scale Django properly that’s why I’m sharing this video with you. So you can make your Django deployment “greater again” (no pun intended).