是否可以在多个配置文件中使用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)
这样,如果用户登录,我可以轻松获取配置文件,因为User有一个get_profile()方法。但是,我想添加UserProfileB。从环顾四周看,似乎起点是创建一个超类用作AUTH_PROFILE_MODULE并让UserProfileA和UserProfileB继承该超类。问题是,我不认为get_profile()方法返回正确的配置文件。它将返回超类的实例。我来自java背景(多态),所以我不确定我应该做什么。
谢谢!
编辑:
我找到了一种方法,通过我在这个网站上发现的“继承黑客”来做到这一点http://djangosnippets.org/snippets/1031/
然而,它工作得非常好,来自java背景,这个东西自动发生,我有点不安,因为有人必须编写这个并称之为“黑客”才能在python中执行此操作。有没有理由为什么python不启用它?
答案 0 :(得分:4)
因此,您将要遇到的问题是,无论您想要什么样的配置文件,都需要将其保存在某种类型的数据库中。基本上django的所有后端都是关系型的,因此持久化对象中的每个字段都存在于表的每一行中。有几种方法可以获得你想要的东西。
Django为inheritance.提供了一些支持您可以使用列出的技术并以多态方式获得合理的结果。
最直接的方法是使用多表继承。大致是:
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...
编辑:重新评论。
关系模型意味着seem to disagree具有面向对象哲学的许多事物。为了使关系有用,它要求关系中的每个元素具有相同的维度,以便关系查询对整个关系有效。由于这是先验已知的,因此在遇到存储在关系中的类的实例之前,该行不能是子类。 django的orm通过将子类信息存储在不同的关系(一个特定于子类的关系)中克服了这种阻抗不匹配,还有其他解决方案,但它们都遵循关系模型的这种基本性质。
如果它能帮助你解决这个问题,我建议看一下在没有ORM的情况下RDBM的持久性如何适用于应用程序。特别是,关系数据库更多地涉及许多行的集合和摘要,而不是一旦从数据库中获取数据就将行为应用于数据。
使用django.contrib.auth
的配置文件功能的具体示例是一个相当无趣的特性,特别是如果使用该模型的唯一方法是获取与特定django.contrib.auth.models.User
实例关联的配置文件数据。如果没有其他查询,则根本不需要django.models.Model
子类。你可以挑选一个普通的python类并将它存储在一个无特征模型的blob字段中。
另一方面,如果您想使用个人资料执行更多有趣的事情,例如搜索位于特定城市的用户,那么所有个人资料都必须拥有他们的城市财产。这与OOP无关,而与关系有关。
答案 1 :(得分:1)
Pinax团队的idios应用程序旨在解决多配置文件问题。您可以调整模型以使基本概要类的继承成为抽象或非抽象。 https://github.com/eldarion/idios
答案 2 :(得分: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的开发人员以这种方式继承工作
答案 3 :(得分: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()