get_or_create and unique_together in Django REST Framework

Implementing get_or_create in django API using Rest Framework, with and without unique_together constrain.

Advert

get_or_create is a frequently used and handy function in Django. In Django DRF you can use it as you would use in a regular application if using functional view or class view for processing the data.

With Django Serializes offering many functionality in the box, I wanted to get this done in serialize level. It's staright forward if you don't have any unique_together constrain set to the key fields.

For demo I am using a Guest Model with name, phone number and email, where email and phone is set to be unique_togethe.


class Guest(models.Model):
  first_name = models.CharField(max_length=300)
  last_name = models.CharField(max_length=300, blank=True)
  phone = models.CharField(max_length=300)
  email = models.EmailField(max_length=300)
  
  class Meta:
    unique_together = ('email', 'phone')

Define a new create function and use get_or_create. You are good to go.


class GuestSerializer(serializers.ModelSerializer):
  last_name = serializers.CharField(required=False)
  id = serializers.ReadOnlyField()
  class Meta:
    model = Guest
    fields = ('id','first_name', 'last_name', 'email', 'phone')

  def create(self, validated_data):
    guest, created = Guest.objects.get_or_create(
      email=validated_data['email'], 
      phone=validated_data['phone'], 
      defaults={
        'first_name': validated_data['first_name'], 
        'last_name': validated_data['last_name']
      })
  return guest

unique_together and get_or_create in DRF

If you have set up unique_together constrains for fields in models then the above code will raise a unique together error before the create functions is invoked.

It's triggered by validation functions in ModelSerializer which inspects unique together before passing control to create function, to get over this a custom validation function to skip the unique together validation will work, because get_or_create is used.


class GuestSerializer(serializers.ModelSerializer):
  last_name = serializers.CharField(required=False)
  id = serializers.ReadOnlyField()
  class Meta:
    model = Guest
    fields = ('id','first_name', 'last_name', 'email', 'phone')

  def run_validators(self, value):
    for validator in copy(self.validators):
      if isinstance(validator, validators.UniqueTogetherValidator):
        self.validators.remove(validator)
    super(GuestSerializer, self).run_validators(value)

  def create(self, validated_data):
    guest, created = Guest.objects.get_or_create(property=validated_data['property'], 
      email=validated_data['email'], 
      phone=validated_data['phone'], 
      defaults={
        'first_name': validated_data['first_name'], 
        'last_name': validated_data['last_name']
      })
  return guest

Comments

Wow ! you have someting to tell us. That's great! Please keep in mind that comments are moderated, we employ rel="nofollow" for links, avoid using a spammy word or a domain in name field, it might end up as a Spam. Thanks for reading.

Last 5 Articles

All Articles >

  1. 9 Ways to Boost the Design of Your Sports Team Website

     
  2. DevOps Tools

     
  3. The Best Marketing Apps to Use with Shopify

     
  4. Tips to Increase Software Development Speed

     
  5. Mitigating Risks In Custom Software Development

     

News Letter

Subscribe to our email newsletter for useful tips and valuable resources, sent out every new article release.