0

是否可以将 Django 的用户身份验证功能与多个配置文件一起使用?

目前我有一个 settings.py 文件,其中包含:

AUTH_PROFILE_MODULE = 'auth.UserProfileA'

和一个models.py文件,里面有这个:

from django.db import models
from django.contrib.auth.models import User

class UserProfileA(models.Model):
    company = models.CharField(max_length=30)
    user = models.ForeignKey(User, unique=True)

这样,如果用户登录,我可以轻松获取配置文件,因为用户有一个 get_profile() 方法。但是,我想添加 UserProfileB。环顾四周,似乎起点是创建一个超类用作 AUTH_PROFILE_MODULE 并让 UserProfileA 和 UserProfileB 都继承自该超类。问题是,我不认为 get_profile() 方法返回正确的配置文件。它将返回超类的一个实例。我来自 java 背景(多态性),所以我不确定我应该做什么。

谢谢!

编辑:

好吧,我找到了一种方法来通过我在此站点http://djangosnippets.org/snippets/1031/上找到的一种称为“继承黑客”的方法来做到这一点

它工作得非常好,但是,来自自动发生这些事情的java背景,我有点不安,因为有人必须对其进行编码并将其称为“hack”才能在python中完成。python没有启用这个功能有什么原因吗?

4

4 回答 4

4

因此,您将遇到的问题是,无论您想要什么配置文件,您都需要将其保存在某种数据库中。基本上所有 django 的后端都是关系的,因此持久对象中的每个字段都存在于表的每一行中。有几种方法可以得到你想要的。

Django 为继承提供了一些支持。 您可以使用列出的技术并以多态的方式获得合理的结果。

最直接的方法是使用多表继承。大致:

class UserProfile(models.Model):
    # set settings.AUTH_PROFILE_MODULE to this class!
    pass

class UserProfileA(UserProfile):
    pass

class UserProfileB(UserProfile):
    pass

要使用它:

try:
    profile = user.get_profile().userprofilea
    # user profile is UserProfileA
except UserProfileA.DoesNotExist:
    # user profile wasn't UserProfileB
    pass
try:
    profile = user.get_profile().userprofileb
    # user profile is UserProfileB
except UserProfileB.DoesNotExist:
    # user profile wasn't either a or b...

编辑:回复,你的评论。

关系模型暗示了许多似乎与面向对象哲学不一致的东西。为了使关系有用,它要求关系中的每个元素都具有相同的维度,以便关系查询对整个关系有效。由于这是先验已知的,因此在遇到存储在关系中的类的实例之前,该行不能是子类。django 的 orm 通过将子类信息存储在不同的关系(特定于子类)中克服了这种阻抗不匹配,还有其他解决方案,但它们都遵循关系模型的这一基本性质。

如果它可以帮助您接受这一点,我建议您查看 RDBM 上的持久性如何在没有 ORM 的情况下适用于应用程序。特别是,关系数据库更多地是关于许多行的集合和摘要,而不是对从数据库中获取的数据应用行为。

使用 的配置文件功能的具体示例django.contrib.auth是一个相当无趣的示例,特别是如果曾经使用该模型的唯一方法是获取与特定django.contrib.auth.models.User实例关联的配置文件数据。如果没有其他查询,则根本不需要django.models.Model子类。您可以腌制一个常规的 Python 类并将其存储在其他无特征模型的 blob 字段中。

另一方面,如果您想用个人资料做更多有趣的事情,例如搜索居住在特定城市的用户,那么所有个人资料都必须为其城市财产建立索引。这与 OOP 无关,而与关系有关。

于 2011-01-03T02:09:30.473 回答
1

Pinax 团队的 idios 应用程序旨在解决多配置文件问题。您可以调整模型以使基本配置文件类的继承是抽象的或非抽象的。 https://github.com/eldarion/idios

于 2011-01-03T02:27:41.017 回答
0

这是我关于如何让多个配置文件工作的问题的答案:

from django.contrib.contenttypes.models import ContentType
class Contact(models.Model):

    content_type = models.ForeignKey(ContentType,editable=False,null=True)

    def save(self):
        if(not self.content_type):
            self.content_type = ContentType.objects.get_for_model(self.__class__)
        self.save_base()

    def as_leaf_class(self):
        content_type = self.content_type
        model = content_type.model_class()
        if(model == Contact):
            return self
        return model.objects.get(id=self.id)

我真的不明白为什么它会起作用,或者为什么 django/python 的开发人员让继承以这种方式工作

于 2011-01-03T02:36:32.667 回答
0

如果您对每个用户都有特定于应用程序的选项,我宁愿建议将它们放入单独的模型中。

一个简化的例子:

class UserSettings(models.Model):
    user = models.ForeignKey(User, primary_key = True)

    # Settings go here
    defaultLocale = models.CharField(max_length = 80, default = "en_US")
    ...

这将像这样使用:

def getUserSettings(request):
    try:
        return UserSettings.objects.get(pk = request.user)
    except UserSettings.DoesNotExist:
        # Use defaults instead, that's why you should define reasonable defaults
        # in the UserSettings model
        return UserSettings()
于 2011-01-03T15:46:01.737 回答