You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中通过User UUID更新Profile时出现404错误的解决咨询

问题描述

我希望通过传递User UUID作为关键字参数来更新用户Profile,配置的URL如下:

path("profile/update/<uuid:pk>", UpdateProfile.as_view(), name="update_profile"),

但尝试更新时出现404错误,View代码如下:

class UpdateProfile(LoginRequiredMixin, UpdateView):
    model = Profile
    user_type_fields = {
        "Buyer": ["photo", "first_name", "last_name", "city"],
        "Celler": ["photo", "name", "city", "address"],
    }

    def get(self, request, *args, **kwargs):
        print(kwargs)
        self.fields = self.user_type_fields[get_user_model().objects.get(pk=kwargs["pk"]).type]
        return super().get(request, *args, **kwargs)

错误信息:

Page not found (404)
No profile found matching the query

我清楚这是因为Django默认用URL中的UUID去查找Profile,但找不到对应记录。如果把View的model改成User,又无法访问Profile模型的字段。目前只能用Profile ID作为参数,但出于安全考虑不想这么做。请问如何通过User UUID作为关键字参数来更新Profile?

补充:User和Profile模型代码

class CustomUser(AbstractBaseUser, PermissionsMixin):
    class UserTypeChoices(models.TextChoices):
        SINGLE_VOLUNTEER = "Single Volunteer", _("Single Volunteer")
        VOLUNTEERS_ORGANISATION = "Volunteers Organisation", _("Volunteers Organisation")
        CIVIL_PERSON = "Civil Person", _("Civil Person")
        MILITARY_PERSON = "Military Person", _("Military Person")

    type = models.CharField(
        max_length=23,
        choices=UserTypeChoices.choices,
    )
    uuid = models.UUIDField(
        primary_key=True,
        default=uuid4,
        unique=True,
        db_index=True,
        editable=False,
    )
    email = models.EmailField(
        _("email address"),
        null=True,
        blank=True,
    )
    phone = PhoneNumberField(
        _("phone"),
        null=True,
        blank=True,
    )
    is_staff = models.BooleanField(
        _("staff status"),
        default=False,
        help_text=_("Designates whether the user can log into this admin site."),
    )
    is_active = models.BooleanField(
        _("active"),
        default=True,
        help_text=_("Designates whether this user should be treated as active. Unselect this instead of deleting accounts."),
    )

    def __str__(self):
        if self.email:
            return str(self.email)
        else:
            return str(self.phone)

    USERNAME_FIELD = "email"

    objects = CustomUserManager()
class Profile(models.Model):
    user = models.OneToOneField(to="accounts.CustomUser", on_delete=models.CASCADE, blank=True, null=True)
    photo = models.ImageField(upload_to="profile/", blank=True, null=True, default="profile/profile_default.png")
    name = models.CharField(_("name"), max_length=150, blank=True, null=True, default=None)
    first_name = models.CharField(_("first name"), max_length=150, blank=True, null=True, default=None)
    last_name = models.CharField(_("last name"), max_length=150, blank=True, null=True, default=None)
    city = models.CharField(_("city"), max_length=150, blank=True, null=True, default=None)
    address = PlainLocationField()

    def __str__(self):
        if self.user.email:
            return str(self.user.email)
        else:
            return str(self.user.phone)
解决方案

核心思路

重写UpdateView的get_object方法,让视图通过URL中的User UUID找到关联的Profile,而非默认用pk查找Profile本身。

方法一:重写get_object(推荐)

修改UpdateProfile视图,添加get_object方法:

class UpdateProfile(LoginRequiredMixin, UpdateView):
    model = Profile
    # 注意:用户类型要和CustomUser的UserTypeChoices完全匹配,原代码中的Buyer/Celler是笔误
    user_type_fields = {
        "Single Volunteer": ["photo", "first_name", "last_name", "city"],
        "Volunteers Organisation": ["photo", "name", "city", "address"],
        "Civil Person": ["photo", "first_name", "last_name", "city", "address"],
        "Military Person": ["photo", "first_name", "last_name", "city", "address"],
    }

    def get_object(self, queryset=None):
        # 通过URL中的pk(User UUID)获取用户
        user = get_user_model().objects.get(pk=self.kwargs["pk"])
        # 自动创建Profile(如果用户还没有的话),避免404
        profile, created = Profile.objects.get_or_create(user=user)
        # 可选:限制只能修改自己的Profile,增强安全性
        if user != self.request.user:
            raise PermissionDenied()
        return profile

    def get(self, request, *args, **kwargs):
        user = get_user_model().objects.get(pk=self.kwargs["pk"])
        self.fields = self.user_type_fields[user.type]
        return super().get(request, *args, **kwargs)

方法二:通过关联字段查找

如果不想修改get_object,可以利用Django的关联查询字段配置:

  1. 修改URL参数名(可选,让语义更清晰):
path("profile/update/<uuid:user_uuid>", UpdateProfile.as_view(), name="update_profile"),
  1. 视图中指定通过Profile的user__uuid字段匹配URL参数:
class UpdateProfile(LoginRequiredMixin, UpdateView):
    model = Profile
    slug_field = "user__uuid"  # 关联到User的uuid字段
    slug_url_kwarg = "user_uuid"  # URL中对应的参数名
    user_type_fields = {
        # 匹配UserTypeChoices的字段配置
        "Single Volunteer": ["photo", "first_name", "last_name", "city"],
        "Volunteers Organisation": ["photo", "name", "city", "address"],
    }

    def get(self, request, *args, **kwargs):
        user = get_user_model().objects.get(pk=self.kwargs["user_uuid"])
        self.fields = self.user_type_fields[user.type]
        return super().get(request, *args, **kwargs)

关键注意点

  • 确保user_type_fields的键和CustomUser.UserTypeChoices的选项完全一致,否则会抛出KeyError
  • 用get_or_create处理Profile不存在的情况,避免出现404
  • 加上权限验证(比如只能修改自己的Profile),防止越权操作

内容的提问来源于stack exchange,提问作者Алексей Василенко

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 22:25:22