【问题标题】:Django: reverse OneToOneField matching without related_nameDjango:反向OneToOneField匹配没有related_name
【发布时间】:2019-09-11 03:44:11
【问题描述】:

我有几个模型代表不同类型的用户配置文件,

class User(models.Model):
  pass

class ProfileA(models.Model):
  user = models.OneToOneField(User, related_name="%(app_label)s_%(class)s_related",)

class ProfileB(models.Model):
  user = models.OneToOneField(User, related_name="%(app_label)s_%(class)s_related",)

class ProfileC(models.Model):
  user = models.OneToOneField(User, related_name="%(app_label)s_%(class)s_related",)

现在,假设我获取了用户实例:如何获取相关的配置文件对象?所有三个配置文件模型(在我的代码中,我有 6 个不同的配置文件模型扩展 BaseProfile 模型,它是抽象的)都有额外的字段,我基本上需要从用户对象实例中访问整个配置文件对象。

【问题讨论】:

    标签: django django-models


    【解决方案1】:

    docs 建议使用hasattr,但在您的情况下可能会有点混乱。

    为了简化这个过程,我将基类 User 模型子类化,然后创建一个自定义方法来获取它自己的配置文件。

    例如:

    from django.db import models
    from django.contrib.auth.models import AbstractUser
    
    class User(AbstractUser):
        def get_profile(self):
            if hasattr(self, 'profile_a'):
                return self.profile_a
            elif hasattr(self, 'profile_b'):
                return self.profile_b
            elif hasattr(self, 'profile_c'):
                return self.profile_c
    
    class ProfileA(models.Model):
        user = models.OneToOneField(User, related_name='profile_a', on_delete=models.CASCADE, primary_key=True)
        name = models.CharField(max_length=45)
    
    class ProfileB(models.Model):
        user = models.OneToOneField(User, related_name='profile_b', on_delete=models.CASCADE, primary_key=True)
        name = models.CharField(max_length=45)
    
    class ProfileC(models.Model):
        user = models.OneToOneField(User, related_name='profile_c', on_delete=models.CASCADE, primary_key=True)
        name = models.CharField(max_length=45)
    

    现在您可以获取任何User 对象的配置文件:

    def view(request):
        user = request.user
        print(user.get_profile())
    

    另外,不要忘记告诉 django 你创建了一个新的用户模型,方法是在你的 settings.py 中添加 AUTH_USER_MODEL = 'yourapp.User'

    【讨论】:

    • 这是最有意义的。谢谢!
    【解决方案2】:

    应用名称是已安装应用中的应用名称,其中点引用替换为下划线,例如应用 myapp

    user = User.objects.get(...)
    a = user.myapp_profilea_related
    b = user.myapp_profileb_related
    c = user.myapp_profilec_related
    

    您可以通过 _meta 属性以编程方式获取这些值,该属性是您的 Meta 子类的一个实例:

    user = User.objects.get(...)
    a = getattr(user, f'{ProfileA._meta.app_label}_{ProfileA._meta.model_name}_related')
    b = getattr(user, f'{ProfileB._meta.app_label}_{ProfileB._meta.model_name}_related')
    c = getattr(user, f'{ProfileC._meta.app_label}_{ProfileC._meta.model_name}_related')
    

    【讨论】:

    • 我的问题是如何在不使用相关名称的情况下获取相关的 121 对象,因为需要猜测。
    猜你喜欢
    • 2012-10-21
    • 2017-04-25
    • 1970-01-01
    • 1970-01-01
    • 2021-01-26
    • 2018-12-03
    • 2021-11-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多