【问题标题】:django.db.utils.ProgrammingError: relation "..." does not existdjango.db.utils.ProgrammingError:关系“...”不存在
【发布时间】:2021-01-05 03:57:12
【问题描述】:

我希望 Django 中的 User 对象链接到 Client 对象(我创建的)。为此,我使用与 Profile 类(我创建的)的一对一链接来扩展 User 模型 链接用户和客户的类配置文件。我按照https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html 的说明进行操作,到目前为止一切顺利。

但是,当我创建用户对象时,默认情况下我无权访问我想要我的用户对象

我的models.py:

from django.contrib.auth.models import User

[...]

class Client(models.Model):
    name = models.CharField(max_length=255)
    address = models.CharField(max_length=255)
    [...]

class Profile(models.Model):
    need_setup = Client.objects.get(name='NEED TO ADD CLIENT IN ADMIN > PROFILES')
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    client = models.ForeignKey(Client, on_delete=models.DO_NOTHING)

@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)

@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    instance.profile.save()

当我进行迁移/运行服务器时出现问题(我的应用程序称为“仪表板”): django.db.utils.ProgrammingError: relation "dashboard_client" does not exist LINE 1: ...nque_id", "dashboard_client"."date_creation" FROM "dashboard... 因为need_setup = Client.objects.get(name='NEED TO ADD CLIENT IN ADMIN > PROFILES')(如果我把它注释掉就没有问题了)。

我可以通过在数据库中手动创建一个名为“NEED TO ADD CLIENT IN ADMIN > PROFILES”的客户端来解决此问题,然后运行我的迁移和部署,但我正在寻找一种更好的方法,尤其是当我在 prod 中从头开始部署。

我试图覆盖apps.py 中的def ready(self) 函数,该函数在应用程序启动时运行。不幸的是,它在运行之前需要有正确的 models.py。

感谢您的想法和想法!

【问题讨论】:

  • 所以,你的问题是你试图在你的Profile 模型中get Client 的一个实例。一开始,您实际上没有任何客户端实例,因此您对Client.objects.get() 的调用理所当然地返回了错误。这就是当您手动将客户端添加到与该名称匹配的数据库时解决此问题的原因。我不确定您对need_setup 字段的目标是什么,但就目前而言,它实际上不是一个字段,它是一个查询集,不应该在模型中。如果你能弄清楚need_setup 应该是什么,我们可能会弄清楚如何解决它
  • 我同意@rchurch4。似乎您想知道哪些配置文件对象是使用来自保存后信号create_user_profileuser 新创建的。在这种情况下,您可以简单地将need_setup 设置为默认值为True 的BooleanField。然后,重写save 方法来检查对象是否有一个client 链接。如果client 仍然为空,则保持need_setup 为True,否则设置为False。
  • 是的,正是我想要的 ^
  • 你们俩都是传奇,非常感谢。我确实从@Scratch'N'Purr 实现了这个想法 - 你可以将它作为答案发布,以便我可以将其标记为已回答吗?伙计们干杯

标签: python django django-models


【解决方案1】:

根据我对您的情况的理解,您希望:

  1. 在创建用户后触发创建配置文件对象并将配置文件对象链接到用户(已使用您的保存后信号完成)。
  2. 确定配置文件对象是否需要配置client(您要解决的问题)

在这种情况下,您将need_setup 字段设置为属性为default=True 的BooleanField。这意味着默认情况下需要设置新创建的任何 Profile 对象。为了安全起见,您可以添加属性editable=False,使该字段不能被外部修改。

class Profile(models.Model):
    need_setup = models.BooleanField(default=True, editable=False)
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    client = models.ForeignKey(Client, on_delete=models.DO_NOTHING)

接下来,您覆盖模型的 save 方法以根据是否填充 client 来切换布尔字段。

class Profile(models.Model):
    need_setup = models.BooleanField(default=True, editable=False)
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    client = models.ForeignKey(Client, on_delete=models.DO_NOTHING)

    def save(self, *args, **kwargs):
        if self.client is None:
            self.need_setup = True
        else:
            self.need_setup = False

        super().save(*args, **kwargs)

另一种解决方案是使用 python 的@property。使用此解决方案,您基本上将need_setup 设置为属性而不是字段。这具有不必在数据库级别创建字段的优点。此解决方案的缺点是您不能在 django 查询集中使用它,例如Profile.objects.filter(need_setup=True),因为 django 查询集使用数据库字段。

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    client = models.ForeignKey(Client, on_delete=models.DO_NOTHING)

    @property
    def need_setup(self):
        return not bool(self.client)

【讨论】:

    猜你喜欢
    • 2021-03-30
    • 2018-05-11
    • 2014-10-25
    • 2019-03-15
    • 2018-03-23
    • 2021-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多