自定义用户模型中的EmbeddedModelField

0 投票
1 回答
1053 浏览
提问于 2025-04-18 00:25

我正在使用django-mongodb-engine来制作一个网站。

我有一个自定义的用户模型,长得像这样:

class User(AbstractUser):
    trigrama = models.CharField(max_length=3, unique=True)
    external_email = models.EmailField(unique=True)
    phone_number = models.CharField(max_length=20, unique=True)

    AbstractUser._meta.get_field_by_name('email')[0]._unique=True

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = [
        'first_name', 'last_name', 'trigrama',
        'external_email', 'phone_number', 'username'
    ]

这个模型运行得很好,但我尝试在用户模型中添加一个嵌入文档:

    permissions = EmbeddedModelField('Permission')

Permission是一个看起来像这样的类:

class Permission(models.Model):
    computers = ListField(EmbeddedModelField('Computer'))
    projects = ListField(EmbeddedModelField('Project'))
    scripts = ListField(EmbeddedModelField('Script'))

现在,当我在命令行中使用User.objects.create()创建用户时,我遇到了以下错误:

Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "C:\Python27\lib\site-packages\django\db\models\manager.py", line 149, in create
    return self.get_query_set().create(**kwargs)
  File "C:\Python27\lib\site-packages\django\db\models\query.py", line 416, in create
    obj.save(force_insert=True, using=self.db)
  File "C:\Python27\lib\site-packages\django\db\models\base.py", line 548, in save
    force_update=force_update, update_fields=update_fields)
  File "C:\Python27\lib\site-packages\django\db\models\base.py", line 668, in save_base
    result = manager._insert([self], fields=fields, return_id=update_pk, using=using, raw=raw)
  File "C:\Python27\lib\site-packages\django\db\models\manager.py", line 215, in _insert
    return insert_query(self.model, objs, fields, **kwargs)
  File "C:\Python27\lib\site-packages\django\db\models\query.py", line 1675, in insert_query
    return query.get_compiler(using=using).execute_sql(return_id)
  File "C:\Python27\lib\site-packages\djangotoolbox\db\basecompiler.py", line 583, in execute_sql
    "field) to None!" % field.name)
IntegrityError: You can't set permissions (a non-nullable field) to None!

我尝试通过设置默认值为Permission()来解决这个问题,使用了:

permissions = EmbeddedModelField('Permission', default=Permission())

但我又遇到了以下错误:

Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "C:\Python27\lib\site-packages\django\db\models\manager.py", line 149, in create
    return self.get_query_set().create(**kwargs)
  File "C:\Python27\lib\site-packages\django\db\models\query.py", line 416, in create
    obj.save(force_insert=True, using=self.db)
  File "C:\Python27\lib\site-packages\django\db\models\base.py", line 548, in save
    force_update=force_update, update_fields=update_fields)
  File "C:\Python27\lib\site-packages\django\db\models\base.py", line 668, in save_base
    result = manager._insert([self], fields=fields, return_id=update_pk, using=using, raw=raw)
  File "C:\Python27\lib\site-packages\django\db\models\manager.py", line 215, in _insert
    return insert_query(self.model, objs, fields, **kwargs)
  File "C:\Python27\lib\site-packages\django\db\models\query.py", line 1675, in insert_query
    return query.get_compiler(using=using).execute_sql(return_id)
  File "C:\Python27\lib\site-packages\djangotoolbox\db\basecompiler.py", line 579, in execute_sql
    connection=self.connection
  File "C:\Python27\lib\site-packages\djangotoolbox\fields.py", line 364, in get_db_prep_save
    (embedded_model, type(embedded_instance)))
TypeError: Expected instance of type <class 'users.models.Permission'>, not <type 'unicode'>.

那么,我应该如何在自定义用户模型中添加嵌入文档呢?

附注:如果我在命令行中输入Permission(),它可以正常实例化,返回一个Permission对象而不是unicode。

1 个回答

3

如果你去看一下关于如何为字段设置默认值的文档,你会发现它需要一个值...或者一个可调用对象。你不能就这样创建实例,这样是不行的(我强调一下):

默认值不能是一个可变对象(比如模型实例、列表、集合等),因为所有新模型实例都会使用同一个对象的引用作为默认值。

当你自己调用它(也就是 Permission())时,你得到的是一个实例,而这个实例会返回一个unicode(它在调用 __unicode__ 函数)。

换句话说,只需要去掉后面的 ()

permissions = EmbeddedModelField('Permission', default=Permission)

其实,这样做可能会有问题,因为它并没有真正保存那个新的权限对象,整个事情可能会变得很麻烦(毕竟这是权限,你需要格外小心)。所以,最好是创建一个函数来包裹这个操作,然后用那个函数:

def get_initial_perms():
    p = Permission()
    p.save()
    return p

# later:
permissions = EmbeddedModelField('Permission', default=get_initial_perms)

另一种类似的解决方案是重写 save() 方法,在调用实际的 save 部分之前,给对象赋予一个权限。

撰写回答