【问题标题】:ForeignKey to AnonymousUser匿名用户的外键
【发布时间】:2020-06-16 03:02:06
【问题描述】:

我想关注这个guideline 并避免使用可为空的 ForeignKey。

我有一个 django User 模型的 ForeignKey。

如果我尝试将 request.user 存储在此模型的实例中,我会收到此错误:

ValueError: Cannot assign "<SimpleLazyObject: <django.contrib.auth.models.AnonymousUser>>":
 "MyModel.user" must be a "User" instance.

我认为避免非无条件数据模式(可为空的外键)是可行的。

我该如何解决这个问题?

【问题讨论】:

    标签: django django-models


    【解决方案1】:

    这些指南建议您创建一个反映匿名用户的用户实例。否则称为哨兵值。您必须通过一些唯一的密钥(可能是用户名)来跟踪它。然后确保它存在并且没有其他人实际使用该密钥创建用户,否则您会遇到其他问题。

    但是,由于上述概述的问题,我不同意这些准则。如果您的数据模型允许可选关系,那么您绝对应该使用 NULL 值。

    关于评论:

    如果您的数据中没有 NULL,那么在处理数据时,您的源代码中将不会出现 NullPointerException :-)

    仅仅因为没有 NULL 字段,并不意味着这些条件不存在。您仍在处理这些边缘情况,但要更改名称和一些语法。您仍然容易受到错误的影响,因为您仍然有很多条件(并且可能更多,因为您现在必须确保您的哨兵值是唯一的)。

    【讨论】:

    • 感谢您对“哨兵价值”的提示。我更新了指南。
    【解决方案2】:

    嘿,这是我第一次尝试回答问题!我是新手,但我最近遇到了类似的错误。我想这是一个幼稚的版本 Nigel222 的答案,它要求通过迁移来做到这一点,但对于另一个需要更简单解决方案的新手来说,这里也许有一些价值。我受到 Ayman Al-Absi 对 post 的回答的影响,这表明您可能需要通过自动生成的主键来引用该用户。

    默认情况下,request.user 在未通过身份验证时为 AnonymousUser。从错误消息看来,AnonymousUser 不能用作 User 表中外键的值。 建议的解决方案:

    from django.contrib.auth.models import User
    # Start by creating a user in your User table called something like anon in some kind of initialization method:
    tempUser= User.objects.create_user(username="anon", email="none", first_name="none", last_name="none")
    tempUser.save()
    #when the user is unauthenticated, before calling a method that takes request as a parameter do:
    if request.user.is_anonymous:
      anonUser = User.objects.get(username='anon')
      request.user=User.objects.get(id=anonUser.id)
    

    给新手的另一条评论。我在models.py 中创建了自己的名为User 的表。这变得令人困惑。我必须使用别名导入它: from .models import User as my_user_table 一开始就叫它 my_user_table 会更好。

    【讨论】:

      【解决方案3】:

      为此目的创建User 的特殊实例。这样做的最佳位置是模型的数据迁移,这将依赖于能够为这个特殊的 User 对象创建一个 ForeignKey。当您部署应用并运行 makemigrations 和 migrate 时,它​​会在数据库中有任何实际用户之前创建特殊用户对象。

      有很多关于创建数据迁移的细节here

      这是一个确保某些 Group 对象在此迁移时存在以用于任何未来部署的示例。

      # Generated by Django 2.2.8 on 2020-03-05 09:53
      
      from django.db import migrations
      
      def apply_migration(apps, schema_editor):
      
          Group = apps.get_model("auth", "Group")
          Group.objects.bulk_create(
              [Group(name="orderadmin"), 
               Group(name="production"),
               Group(name="shipping")]
          )
      
      def revert_migration(apps, schema_editor):
          Group = apps.get_model("auth", "Group")
          Group.objects.filter(name__in=["orderadmin", "production", "shipping"]).delete()
      
      
      class Migration(migrations.Migration):
      
          dependencies = [
              ('jobs', '0034_auto_20200303_1810'),
          ]
      
          operations = [
              migrations.RunPython(apply_migration, revert_migration)
          ]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-08-07
        • 2016-09-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多