Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django REST Framework: SlugRelatedField for indirectly-related attribute?

I have a Profile model that has a one-to-one relationship with Django's User model, and I have another model, called Permission (unrelated to Django's internal idea of permissions), that has a foreign key to Profile. Like this: (I've removed most of the fields here, for simplicity)

from django.db import models
from django.contrib.auth.models import User as DjangoUser

class Account(models.Model):
    name = models.CharField(max_length=200, db_index=True)

class Profile(models.Model):
    django_user = models.OneToOneField(DjangoUser)
    default_account = models.ForeignKey(Account)

class Permission(models.Model):
    # Which user has the permission
    user = models.ForeignKey(Profile, db_index=True)
    # Which account they have the permission on
    account = models.ForeignKey(Account, db_index=True)

I want to make a serializer for Permission, that will create objects like this:

{
  "user": "[email protected]",
  "account": 123
}

where the value of "account" is the account's primary key (so that's easy, I can use a PrimaryKeyRelatedField) and the value of "user" is the user's email address (this is the part I haven't figured out yet, because the email address is not stored directly on the Profile object, it's on the associated DjangoUser object). Note also that this is NOT read-only - when creating a Permission it does need to be able to deserialize from an email address to a Profile object.

Some things I have tried so far, for representing the user on the Permission serializer ...

1.

user = serializers.RelatedField(read_only=False)

With this one, if I POST an email address (or primary key or anything else) as the "user", it returns a 400 error saying {"user": "This field is required."}, as if I didn't include the field at all.

2.

user = serializers.SlugRelatedField(slug_field='django_user.email')

With this one, I get AttributeError: 'Profile' object has no attribute 'django_user.email'. Same thing happens if I use 'django_user__email'.

Any ideas?

like image 554
Avril Avatar asked Oct 02 '14 18:10

Avril


People also ask

How do you pass extra context data to Serializers in Django REST framework?

In function-based views, we can pass extra context to serializer with “context” parameter with a dictionary. To access the extra context data inside the serializer we can simply access it with “self. context”. From example, to get “exclude_email_list” we just used code 'exclude_email_list = self.

What is SlugRelatedField Django?

The SlugRelatedField provided by Django REST framework, like many of the related fields, is designed to be used with objects that already exist. Since you are looking to reference objects which already exist, or object which need to be created, you aren't going to be able to use it as-is.

How do I change the foreign key value in Django REST framework?

As stated in the documentation, you will need to write your own create() and update() methods in your serializer to support writable nested data. You will also need to explicitly add the status field instead of using the depth argument otherwise I believe it won't be automatically added to validated_data .

How do you get a foreign key field name instead of ID in Django REST framework?

If you want to show any field of foreign key instead of id then you can use StringRelatedField.


1 Answers

According to Django REST Framework serializer reference (http://www.django-rest-framework.org/api-guide/fields/#core-arguments):

The name of the attribute that will be used to populate the field. May be a method that only takes a self argument, such as URLField(source='get_absolute_url'), or may use dotted notation to traverse attributes, such as EmailField(source='user.email').

So, if source='user.email' is not working, you can try to create a method (e.g. get_user_email), use it in source field and make it return the user email manually.

like image 96
Danilo Freitas Avatar answered Sep 26 '22 02:09

Danilo Freitas