因此,我在 Django 中有一个 UserProfile,其中包含整个项目所需的某些字段——生日、居住地等——它还包含许多就逻辑而言实际上并不重要的信息——家乡,关于我等UserProfile 无需直接修改模型。也就是说,我希望新实例的管理员能够根据用户的特定需求动态创建用户的新属性。由于 ORM 的性质,这可能吗?
2 回答
一个简单的解决方案是创建一个名为 UserAttribute 的新模型,该模型具有一个键和一个值,并将其链接到 UserProfile。然后你可以将它用作 django-admin 中的内联。这将允许您通过管理员向 UserProfile 添加任意数量的新属性:
模型.py
class UserAttribute(models.Model):
key = models.CharField(max_length=100, help_text="i.e. Age, Name etc")
value = models.TextField(max_length=1000)
profile = models.ForeignKey(UserProfile)
管理员.py
class UserAttributeInline(admin.StackedInline):
model = UserAttribute
class UserProfile(admin.ModelAdmin):
inlines = [UserAttibuteInline,]
这将允许管理员添加一长串属性。限制是您不能对输入进行任何验证(除了确保它是有效文本之外),您也仅限于可以用简单的英语描述的属性(即您将无法对它们执行很多登录) 并且您将无法真正比较 UserProfiles 之间的属性(无论如何都没有很多数据库命中)
您可以以序列化状态存储其他数据。这可以为您节省一些数据库命中并稍微简化您的数据库结构。如果您打算仅将数据用于显示目的,这可能是最佳选择。
示例实现(未测试)::
import yaml
from django.db import models
class UserProfile(models.Model):
user = models.OneToOneField('auth.User', related_name='profile')
_additional_info = models.TextField(default="", blank=True)
@property
def additional_info(self):
return yaml.load(self._additional_info)
@additional_info.setter
def additional_info(self, user_info_dict):
self._additional_info = yaml.dump(user_info_dict)
例如,当您分配给profile.additional_info
字典时,它会被序列化并存储在其中_additional_info
(不要忘记稍后保存实例)。然后,当你访问时additional_info
,你会得到那个 python 字典。
我想,您也可以编写一个自定义字段来处理这个问题。
更新(根据您的评论):
因此,这里的实际问题似乎是如何为用户配置文件自动创建和验证表单。(不管你是使用序列化选项还是复杂的数据结构,它仍然存在。)
而且由于您可以轻松创建动态表单[1],因此主要问题是如何验证它们。
考虑一下...管理员无论如何都必须为每个自定义字段指定验证器(或字段类型),对吗?所以你需要某种配置选项——比如说,
CUSTOM_PROFILE_FIELDS = (
{
'name': 'user_ip',
'validators': ['django.core.validators.validate_ipv4_address'],
},
)
然后,当您初始化表单时,根据此设置定义字段及其验证器。
[1] 另请参阅Jacob Kaplan-Moss 关于动态表单生成的这篇文章。但是,它不处理验证。