我想要一个带有保留字段的Django模型,这样没人能直接设置它,但是它的值是在节省时间生成的。例如,这对于生成用户令牌很有用,并且我想防止开发人员直接为令牌密钥设置值。同时,我希望能够像对待其他字段一样对待该字段,因此可以使用__
进行查询中的字段查找,或者将令牌检索为:
token = Token.objects.get(key='c331054c00494f6a22f0ebde7a32bf9d4619b988')
所以在我看来,做这样的事情:
Token.key = 'my-token-key'
应该失败,甚至实例化也应该失败:
token = Token(key='my-token-key')
到目前为止,我想出了这个解决方案,但是我有点担心我的更改可能会破坏某些Django工作流程,因为我不确定我的更改会影响什么:
import binascii
import datetime
import os
from django.contrib.auth import get_user_model
from django.db import models
class Token(models.Model):
"""
An access token that is associated with a user.
"""
id = models.AutoField(primary_key=True)
# By default `get_attname` returns the field `name`,
# but in my case the attribute name is different
_key = models.CharField(max_length=40, unique=True, name='key', db_column='key')
_key.get_attname = lambda: '_key'
name = models.CharField(max_length=255)
user = models.ForeignKey(get_user_model(), related_name='tokens')
created = models.DateTimeField(auto_now_add=True)
last_access_time = models.DateTimeField(null=True, blank=True)
expires = models.DateField(
null=True,
blank=True,
help_text="Leave empty for non-expiring tokens. "
"Once the token has expired you can not extend its validity.",
)
@property
def key(self):
return self._key
@key.setter
def key(self, value):
raise ValueError("Can not set key directly. It is automatically generated when saving the model.")
def save(self, *args, **kwargs):
if not self._key:
self._key = self._generate_key()
super(Token, self).save(*args, **kwargs)
@staticmethod
def _generate_key():
return binascii.hexlify(os.urandom(20)).decode()
@property
def expired(self):
return bool(self.expires and self.expires < datetime.date.today())
def __str__(self):
return '{} - {}'.format(self.user, self.name)
class Meta:
verbose_name = "User Token"
verbose_name_plural = "User Tokens"
unique_together = (('name', 'user'),)
如您所见,我尝试覆盖键字段的get_attname
方法(之所以需要,是因为字段名称和属性相同,这会导致加载表单时出错)。这似乎很好,但是我想知道这是否会导致运行查询的问题。
也许有一种更简单的方法可以做到这一点,但我找不到更好的方法。
P.S .:我在Django 1.11上使用python2
非常感谢大家!