ExTexan
ExTexan

Reputation: 453

How to get TextField to render in API Browser in DRF?

Using DRF, I have a User model that includes an Address field, which is a TextField. When I view the UserList endpoint in the API Browser, Address looks like this:

"address": "<django.db.models.fields.TextField>",

From the documentation, I thought I needed this in my serializer:

    address = serializers.CharField(
        max_length=1000,
        style={'base_template': 'textarea.html'},
    )

...but that didn't fix the problem. The same thing is happening with PhoneNumberField type fields:

"phone_number": "<phonenumber_field.modelfields.PhoneNumberField>",

I redefined them in my serializer as CharField.

UPDATE:

My models and serializers are a bit more complex than usual because I'm splitting the Address, Country, and three phone fields out into separate classes so they can be included in several different models.

My User models:

class User(AbstractUser, AddressPhoneModelMixin):
    objects = UserProfileManager()

    USERNAME_FIELD = 'email'

    type = models.CharField(
        max_length=25,
    )
    title = models.CharField(
        max_length=100,
        blank=True,
        null=True,
    )
    timezone = models.CharField(
        max_length=50,
    )
    birthdate = models.DateTimeField(
        blank=True,
        null=True,
    )
    is_verified = models.BooleanField(
        default=False,
    )
    email = models.EmailField(
        unique=True,
        db_index=True,
    )

This is the model class for Address and Phone fields:

class AddressPhoneModelMixin(object):
    address = models.TextField(
        blank=True,
        null=True,
    )
    country = models.ForeignKey(
        Country,
        on_delete=models.SET_NULL,
        blank=True,
        null=True,
    )
    phone_number = PhoneNumberField(
        blank=True,
        null=True,
    )
    mobile_number = PhoneNumberField(
        blank=True,
        null=True,
    )
    fax_number = PhoneNumberField(
        blank=True,
        null=True,
    )

    class Meta:
        abstract = True

The User serializer:

class UserSerializer(AddressPhoneSerializerMixin, serializers.ModelSerializer):

    permission_classes = (permissions.IsAuthenticated,)

    url = serializers.HyperlinkedIdentityField(view_name="users:user-detail")

    class Meta:
        model = User
        fields = (
            'url',
            'id',
            'type',
            'username',
            'first_name',
            'last_name',
            'full_name',
            'email',
            'address',
            'country',
            'phone_number',
            'mobile_number',
            'fax_number',
            'is_superuser',
            'is_staff',
            'is_active',
            'is_verified',
            'date_joined',
            'last_login',
        )

The Address and Phone fields serializer:

class AddressPhoneSerializerMixin(serializers.Serializer):

    address = serializers.CharField(
        max_length=1000,
        style={'base_template': 'textarea.html'},
    )
    country = serializers.HyperlinkedIdentityField(
        view_name='countries:country-detail'
    )
    phone_number = serializers.CharField(
        max_length=31,
    )
    mobile_number = serializers.CharField(
        max_length=31,
    )
    fax_number = serializers.CharField(
        max_length=31,
    )

    class Meta:
        abstract = True

And, finally, the User views:

class UserList(ListCreateAPIView):
    permission_classes = (permissions.IsAuthenticated,)
    queryset = User.objects.all()
    serializer_class = UserSerializer

class UserDetail(RetrieveUpdateAPIView):
    permission_classes = (permissions.IsAuthenticated,)
    queryset = User.objects.all()
    serializer_class = UserSerializer

I'll include an example from the API Browser that includes all of the fields in question. Note that Country shows as expected.

"email": "[email protected]",
"address": "<django.db.models.fields.TextField>",
"country": "http://virticl.api/countries/1/",
"phone_number": "<phonenumber_field.modelfields.PhoneNumberField>",
"mobile_number": "<phonenumber_field.modelfields.PhoneNumberField>",
"fax_number": "<phonenumber_field.modelfields.PhoneNumberField>",

Upvotes: 1

Views: 1167

Answers (1)

RishiG
RishiG

Reputation: 2830

Your abstract model mixin should be a models.Model subclass:

class AddressPhoneModelMixin(models.Model):
    ...

You'll also need to put it to the left in the order of base classes for your user model as inheritance is processed from right to left:

class User(AddressPhoneModelMixin, AbstractUser):
    ...

NOTE: to specify serializer fields, you can use fields = '__all__' instead of listing them individually. If there are just one or two missing, you can use exclude instead.

Upvotes: 1

Related Questions