django.db.utils.ProgrammingError:无法仅在 Postgres 中调整类型“用户”

问题描述 投票:0回答:2

我有一个非常奇怪的错误,我似乎无法弄清楚。我已经解决了如何修复它,但这对其他人来说可能是一个奇怪的错误,所以我还是发布了。

我有这个查看功能,允许用户邀请团队成员加入他们的团队。

@login_required
def invite_team_member(request):
    if request.method == "POST":
        form = forms.InviteTeamMemberForm(request.POST, team=request.user.profile.team)
        if form.is_valid():
            user = form.clean_username_or_email()
            try:
                models.TeamInvite.objects.create(from_user=request.user, to_user=user, team=request.user.profile.team)
                message = _("User successfully invited")
            except IntegrityError:
                message = _("This user has already been invited to your team")
            except ValidationError as e:
                if e.code == "team_full":
                    message = _("Your team is full, no further users can be invited")
                else:
                    raise e

            return render(
                request,
                "tracker/tracker_home/invite_team_member.html",
                {"invite_team_member_form": form, "message": message},
            )
    else:
        form = forms.InviteTeamMemberForm(team=request.user.profile.team)
    return render(request, "tracker/tracker_home/invite_team_member.html", {"invite_team_member_form": form})

用户在表单中输入用户名或电子邮件,表单将确定邀请使用该用户名或电子邮件的用户是否有效。

class InviteTeamMemberForm(forms.Form):
    username_or_email = forms.CharField(label=_("Username or Email"))

    def __init__(self, *args, **kwargs):
        self.team: models.Team = kwargs.pop("team")
        super().__init__(*args, **kwargs)

    def clean_username_or_email(self):
        data = self.cleaned_data["username_or_email"]

        try:
            user = User.objects.get(Q(username__iexact=data) | Q(email__iexact=data))
            if user.profile.team == self.team:
                raise ValidationError(_("This user cannot be invited since they are already on this team"))
            return user
        except User.DoesNotExist:
            raise ValidationError(_("A user with that username or email doesn't exist."))

现在这就是奇怪的地方。这对于 Sqlite 数据库来说效果很好,但是对于 Postgres,它会抛出这个堆栈跟踪。

Internal Server Error: /tracker/data/invite-team-member/
Traceback (most recent call last):
  File "/home/raymonddevries/PycharmProjects/virtualenvs/tourdeskagit/lib/python3.9/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
psycopg2.ProgrammingError: can't adapt type 'User'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/raymonddevries/PycharmProjects/virtualenvs/tourdeskagit/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/home/raymonddevries/PycharmProjects/virtualenvs/tourdeskagit/lib/python3.9/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/raymonddevries/PycharmProjects/virtualenvs/tourdeskagit/lib/python3.9/site-packages/sentry_sdk/integrations/django/views.py", line 67, in sentry_wrapped_callback
    return callback(request, *args, **kwargs)
  File "/home/raymonddevries/PycharmProjects/virtualenvs/tourdeskagit/lib/python3.9/site-packages/django/contrib/auth/decorators.py", line 21, in _wrapped_view
    return view_func(request, *args, **kwargs)
  File "/home/raymonddevries/PycharmProjects/tourdeskagit/tracker/views.py", line 72, in invite_team_member
    user = form.clean_username_or_email()
  File "/home/raymonddevries/PycharmProjects/tourdeskagit/tracker/forms.py", line 32, in clean_username_or_email
    user = User.objects.get(Q(username__iexact=data) | Q(email__iexact=data))
  File "/home/raymonddevries/PycharmProjects/virtualenvs/tourdeskagit/lib/python3.9/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/home/raymonddevries/PycharmProjects/virtualenvs/tourdeskagit/lib/python3.9/site-packages/django/db/models/query.py", line 431, in get
    num = len(clone)
  File "/home/raymonddevries/PycharmProjects/virtualenvs/tourdeskagit/lib/python3.9/site-packages/django/db/models/query.py", line 262, in __len__
    self._fetch_all()
  File "/home/raymonddevries/PycharmProjects/virtualenvs/tourdeskagit/lib/python3.9/site-packages/django/db/models/query.py", line 1324, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "/home/raymonddevries/PycharmProjects/virtualenvs/tourdeskagit/lib/python3.9/site-packages/django/db/models/query.py", line 51, in __iter__
    results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
  File "/home/raymonddevries/PycharmProjects/virtualenvs/tourdeskagit/lib/python3.9/site-packages/django/db/models/sql/compiler.py", line 1175, in execute_sql
    cursor.execute(sql, params)
  File "/home/raymonddevries/PycharmProjects/virtualenvs/tourdeskagit/lib/python3.9/site-packages/django/db/backends/utils.py", line 98, in execute
    return super().execute(sql, params)
  File "/home/raymonddevries/PycharmProjects/virtualenvs/tourdeskagit/lib/python3.9/site-packages/sentry_sdk/integrations/django/__init__.py", line 500, in execute
    return real_execute(self, sql, params)
  File "/home/raymonddevries/PycharmProjects/virtualenvs/tourdeskagit/lib/python3.9/site-packages/django/db/backends/utils.py", line 66, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "/home/raymonddevries/PycharmProjects/virtualenvs/tourdeskagit/lib/python3.9/site-packages/django/db/backends/utils.py", line 75, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "/home/raymonddevries/PycharmProjects/virtualenvs/tourdeskagit/lib/python3.9/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "/home/raymonddevries/PycharmProjects/virtualenvs/tourdeskagit/lib/python3.9/site-packages/django/db/utils.py", line 90, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/home/raymonddevries/PycharmProjects/virtualenvs/tourdeskagit/lib/python3.9/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: can't adapt type 'User'

我不知道幕后是否发生了一些我错过的事情。单步执行代码时,数据库在执行

user = User.objects.get(Q(username__iexact=data) | Q(email__iexact=data))
时可以很好地检索用户,但是当用户使用
form.clean_username_or_email()
返回视图时,会发生错误。同样,这只发生在 postgres 上,而不是 sqlite 上。

如果有人了解这里发生的事情,请告诉我。我猜

form.clean_username_or_email()
并不意味着直接从视图函数调用。仍然很奇怪,这会引发数据库特定的错误。

python django postgresql django-forms django-orm
2个回答
1
投票

我的解决方案是使用

user = form.cleaned_data["username_or_email"]
而不是
user = form.clean_username_or_email()
相关文档。


0
投票

这非常令人费解,但事实证明,这可能是由于代码中的上游错误,再加上 django 的 EmailFormField 的过度热心清理所致。

我遇到了同样的问题,结果发现我的

email
变量不是电子邮件,而是用户的字符串表示形式 其中包含用户的电子邮件

以django的PasswordResetForm为例:

unclean_email = 'User 1: ([email protected])'
form = PasswordResetForm(data={"email": unclean_email})
form.is_valid()  # Somehow is True!!!
cleaned_email = form.cleaned_data['email']  # This is stripped to [email protected]

User.objects.get(email__iexact=cleaned_email)  # Works
User.objects.get(email__iexact=unclean_email)  # Raises the error above

我怀疑 SQLite 正在执行 LIKE 而不是 POSTGRES 优化的不区分大小写的匹配,这很可能产生结果并解释为什么 OP 能够将代码与 SQLite 一起使用。

© www.soinside.com 2019 - 2024. All rights reserved.