0
votes

I'm creating an API, using Django. I need to create a LogIn for users. So I used the default Django User class and authentication to do that.
But there's a problem. The API for the LogIn (in the /users/login/ endpoint) is defined with the following format: {"user":value, "pass":value}.
And the User model given by Django has two important fields: "username" and "password".
As I said before, I want them to be "user" instead of "username", and "pass" instead of "password". Because that's how the JSON in the POSTs requests will be like in the front-end.
I know I can make a RenameField, but that will only change the column name in the database, it won't change how Django asks for the username and password in the body of the POST request.

I need to send (in a POST request in postman) a JSON to the /users/login/ endpoint, with the following format: {"user":value, "pass":value}.
But the Django User model doesn't know what are those fields, it doesn't need user, it needs username, and it doesn't need pass, it needs password, so I'm getting an error.
I need to change somehow the keys "user" and "pass" in the given JSON to be "username" and "password". Or, to change the field names in the User model. Otherwise, the response will be:

{
    "username": [
        "This field is required."
    ],
    "password": [
        "This field is required."
    ]
}

Because, as I said, Django is getting "user" and "pass", and it doesn't recognize those keys... It needs "username" and "password" fields.
i.e: I need to change somehow from:

{
    "user": value,
    "pass": value
}

to:

{
    "username": value,
    "password": value
}

Or viceversa.
I've tried not to create my own User model, and to use the model given by Django, I think it's not a good idea to create one...
I think I can add a new file called serializer.py and do something there but I'm not sure how, and I didn't found anything in the documentation.

If they're useful, these are my files.
urls.py:

from rest_framework.authtoken.views import obtain_auth_token
from django.contrib import admin
from catanAPI.catan import views
from django.urls import path

urlpatterns = [
    path('admin/', admin.site.urls),
    path('users/login/', obtain_auth_token)
]

settings.py

INSTALLED_APPS = [
    #...
    'django.contrib.auth',
    'rest_framework',
    'rest_framework.authtoken'
    #...
]

AUTH_USER_MODEL = 'auth.User'

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
    ]
}

I know this question may be stupid or something, but I'm new in Django, and I'm trying to learn.

2
what do you mean by I need to change the keys in the JSON given in the request.? Also how are you getting it? Can you please share the code for that? - ruddra
@ruddra I've edited the question. Thanks for answering. - Octaviotastico
My question for you is what are you trying to achieve by shortening the names? You are going to have to put in a whole array of workarounds to make this work. - Tim
I have to implement the API as they told me to. I can't use the long names. I think they did that in purpose. - Octaviotastico

2 Answers

3
votes

I think rather than changing the Model Fields, you should change in the view. You can override the ObtainAuthToken view, like this:

from django.utils.translation import gettext as _
# serializer
class CustomAuthTokenSerializer(serializers.Serializer):
    user = serializers.CharField(label=_("User"))

    def __init__(self, *args, **kwargs):
        super(CustomAuthTokenSerializer, self).__init__(*args, **kwargs)
        self.fields['pass'] = serializers.CharField(
            label=_("Pass"),
            style={'input_type': 'password'},
            trim_whitespace=False
        )
    def validate(self, attrs):
        username = attrs.get('user')
        password = attrs.get('pass')

        if username and password:
            user = authenticate(request=self.context.get('request'),
                                username=username, password=password)

            # The authenticate call simply returns None for is_active=False
            # users. (Assuming the default ModelBackend authentication
            # backend.)
            if not user:
                msg = _('Unable to log in with provided credentials.')
                raise serializers.ValidationError(msg, code='authorization')
        else:
            msg = _('Must include "username" and "password".')
            raise serializers.ValidationError(msg, code='authorization')

        attrs['user'] = user
        return attrs

 # view
 from rest_framework.authtoken.views import ObtainAuthToken

 class CustomObtainAuthToken(ObtainAuthToken):
     serailizer_class = CustomAuthTokenSerializer

 # urls
 path('users/login/', CustomObtainAuthToken.as_view())
0
votes

You can write your custom user:

application/models.py

from django.contrib.auth.models import AbstractUser
from django.db import models

class User(AbstractUser):
    """
    Custom User Model 
    """

    user = models.CharField(max_length=255, unique=True)
    pass_w = models.CharField(max_length=50)
    email = models.CharField(max_length=255, unique=True)

    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = ["user"]

    def __str__(self):
        return self.email

project/settings.py

AUTH_USER_MODEL = 'application.User'