Quantcast
Channel: Active questions tagged rest - Stack Overflow
Viewing all articles
Browse latest Browse all 4797

Why is django-ninja PUT endpoint not using value from request body but instead is returning the default value for field to be updated (ModelSchema)?

$
0
0

Goal

I'm trying to use a Django Ninja API endpoint (with Django Ninja's ModelSchema) to update the time zone preference (tz_preference*) field on my Django app's user model.

*Note: The tz_preference field has a default value and is limited to a list of choices.

Problem

When I test out the API endpoint using /api/docs, the response keeps returning the tz_preference field's default value ("America/Denver") even though I give it other valid values in the request body ("Pacific/Honolulu", "America/Chicago", etc.).

I know that my tz_preference field has a default value of "America/Denver", so this is most likely why the response body is {"tz_preference": "America/Denver"}, but I'm not sure why it's sticking with the default instead of using the value I give it in the request body.

Code

models.py

from django.db import modelsfrom django.contrib.auth.models import PermissionsMixinfrom django.contrib.auth.validators import ASCIIUsernameValidatorfrom django.utils.translation import gettext_lazy as _from timezone_field import TimeZoneFieldfrom zoneinfo import ZoneInfoTZ_CHOICES = [    (ZoneInfo('Pacific/Honolulu'), 'Pacific/Honolulu'),    (ZoneInfo('America/Anchorage'), 'America/Anchorage'),    (ZoneInfo('America/Los_Angeles'), 'America/Los_Angeles'),    (ZoneInfo('US/Arizona'), 'US/Arizona'),    (ZoneInfo('America/Denver'), 'America/Denver'),    (ZoneInfo('America/Chicago'), 'America/Chicago'),    (ZoneInfo('America/New_York'), 'America/New_York'),]class CustomUser(AbstractBaseUser, PermissionsMixin):    username_validator = ASCIIUsernameValidator()    username = models.CharField(        _("username"),        max_length=150,        unique=True,        db_index=True,        validators=[username_validator],        error_messages={"unique": _("A user with that username already exists."),        },    )    email = models.EmailField(        _("email address"),        unique=True,        db_index=True,        help_text=_("Required."        ),        error_messages={"unique": _("A user with that email address already exists."),        },    )    is_staff = models.BooleanField(_("staff status"), default=False,)    is_active = models.BooleanField(_("active"), default=True,)""" -----------------FIELD I'M TRYING TO CHANGE------------------- """    tz_preference = TimeZoneField(        use_pytz=False,        choices=TZ_CHOICES,        default="America/Denver",        choices_display="STANDARD",    )""" -------------------------------------------------------------- """    class CAT_CHOICES(models.TextChoices):        S = 'STUDENT', _('Student')        I = 'INSTRUCTOR', _('Instructor')    category = models.CharField(max_length=10, choices=CAT_CHOICES.choices)    objects = TerpUserManager()    EMAIL_FIELD = "email"    USERNAME_FIELD = "username"    REQUIRED_FIELDS = ["email", "category"]

Sorry if I included too much of the code for my custom user model. Since I'm wondering if required fields are causing the unexpected behavior, I left them in.

api.py

# do ye django ninja stufffrom ninja import NinjaAPIapi = NinjaAPI()# django models stuff (to get my custom user model)from django.contrib.auth import get_user_modelUser = get_user_model()# ninja schema stufffrom ninja import Schema, ModelSchema"""------------------------ SCHEMAS ------------------------------"""class UserTimezoneSchema(ModelSchema):    class Meta:        model = User        fields = ['tz_preference']class NotFoundSchema(Schema):    message: str"""----------------------- ENDPOINTS -----------------------------"""@api.put("/member/{member_id}", response={200: UserTimezoneSchema, 404: NotFoundSchema})def change_tz(request, member_id: int, data: UserTimezoneSchema):    try:        member = User.objects.get(pk=member_id)        member.tz_preference = data.tz_preference        member.save()    except User.DoesNotExist as e:        return 404, {'message': 'User does not exist'}

Request and Response info

Request (PUT /api/member/{member_id})

  • path: member_id: 1
  • body: {"tz_preference": "Pacific/Honolulu"}

CURL

curl -X 'PUT' \'http://127.0.0.1:8000/api/member/1' \  -H 'accept: application/json' \  -H 'Content-Type: application/json' \  -d '{"tz_preference": "Pacific/Honolulu"}'

Response

  • Code: 200

Body

{"tz_preference": "America/Denver"}

Headers

content-length: 35 content-type: application/json; charset=utf-8 cross-origin-opener-policy: same-origin date: Mon,01 Jul 2024 18:02:59 GMT referrer-policy: same-origin server: WSGIServer/0.2 CPython/3.10.14 x-content-type-options: nosniff x-frame-options: DENY 

Responses (bottom section of readout of Django Ninja API auto docs)

screenshot of Responses readout from Django Ninja API documentation

What I think is going wrong:

The image I've included above of the response schemas for this endpoint from the API documentation that Django Ninja automatically generates suggests to me that the default value is automatically set regardless of what the request body is, but I don't have any experience interpreting this automatically generated documentation, so I'm not sure.

And if the problem is due to the default value for this field in my model, I have no idea how to overcome that.

Other possibilities (though these seem less likely to me)

  • Maybe it's because I'm submitting plain strings to the server, but the choices for this field are defined as ZoneInfo objects (I doubt this is the case because plain text data is the only kind of data that can really be submitted through the API, right?)
  • Maybe I should be using a PATCH method instead of PUT
  • Maybe it's not working because my Django project is using csrf protection but I haven't enabled that on the API I construct using Django Ninja
  • Maybe it's because I am trying to only change a single field but there are other required fields that I am not including in the request

Viewing all articles
Browse latest Browse all 4797

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>