Python (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.

<br />
class PostViewSet(viewsets.ModelViewSet):<br />
  queryset         = Post.objects.all()<br />
  serializer_class = serializers.PostSerializer</p>
<p>  def perform_create(self, serializer):<br />
    kwargs = {<br />
      'user': self.request.user # Change 'user' to you model user field.<br />
    }</p>
<p>    serializer.save(**kwargs)<br />

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

<br />
class UserCreateMixin(object):<br />
  &quot;&quot;&quot;<br />
  By default the user field is &quot;user&quot; you can change it<br />
  to your model &quot;user&quot; field.</p>
<p>  Usage:<br />
  class PostViewSet(UserCreateMixin, viewsets.ModelViewSet):<br />
    # ViewsSet required info...<br />
    user_field = 'creator'<br />
  &quot;&quot;&quot;<br />
  user_field = 'user'</p>
<p>  def get_user_field(self):<br />
    &quot;&quot;&quot;<br />
    You can dynamically change the user field<br />
    &quot;&quot;&quot;<br />
    return self.user_field</p>
<p>  def perform_create(self, serializer):<br />
    kwargs = {<br />
      self.get_user_field(): self.request.user<br />
    }</p>
<p>    serializer.save(**kwargs)<br />

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:

<br />
angular.controller('ImageUploadFormCtrl', function($scope, Photo){<br />
  $scope.submitForm = function(isValid){<br />
    if(isValid){<br />
      f = new FileReader(); // or $window.FileReader()</p>
<p>      f.onload = function () {<br />
        $scope.formData.image = f.result; // This is a base64 string</p>
<p>        Photo.save({}, $scope.formData).$promise.then(function(data){<br />
          // 200 Response<br />
          alert('Client image successfully updated.');<br />
        }, function(error){<br />
          // 400 Response<br />
          console.log('Error', error);<br />
          alert('An error has ocurred.');<br />
        })<br />
      };      </p>
<p>      // Read the file selected on the field with ID &quot;image-field&quot;<br />
      f.readAsDataURL(document.getElementById('image-field').files[0]);<br />
    }<br />
  }<br />
});<br />

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

<br />
import base64, uuid<br />
from django.core.files.base import ContentFile</p>
<p>class Base64ImageField(serializers.ImageField):<br />
  def to_internal_value(self, data):<br />
    if isinstance(data, basestring) and data.startswith('data:'): # You can change &quot;data:&quot; to &quot;data/image:&quot;<br />
      format, imgstr = data.split(';base64,')<br />
      ext  = format.split('/')[-1]<br />
      id   = uuid.uuid4()<br />
      data = ContentFile(base64.b64decode(imgstr), name=id.urn[9:])</p>
<p>    return super(Base64ImageField, self).to_internal_value(data)</p>
<p>class PhotoSerializer(serializers.ModelSerializer):<br />
  image = Base64ImageField(allow_empty_file=False)</p>
<p>  class Meta:<br />
    fields           = ('id', 'image')<br />
    model            = Photo<br />
    read_only_fields = ('id', )<br />

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




Require activated virtualenv on PIP

I highly recommended to separate your working environments so every project has their own set of packages. To do this just edit the ~/.bash_profile file.

<br />
export PIP_REQUIRE_VIRTUALENV=true<br />
# define a &quot;global pip&quot; function to use outside virtualenv:<br />
gpip(){<br />
    PIP_REQUIRE_VIRTUALENV=&quot;&quot; pip &quot;$@&quot;<br />
}<br />

After that, reload the source file with this command source ~/.bash_profile.