我正在用 django 建立一个照片共享站点,允许用户创建组来共享照片。我在创建一个合适的用户数据模型/逻辑来满足我的所有要求时遇到问题。
基本要求是:
- 允许用户 A 创建一个组,他可以在其中添加其他用户(用户 B)
- 如果必须添加到组的用户 B 已经存在,那么我们将使用这个现有的用户 B 添加到代表组的组模型的 manytomany 字段
- 如果用户 B 不存在,我们将创建一种“虚拟”用户。将 user_active 设置为 false。这是因为用户 B 尚未设置任何类型的验证或密码。
现在,如果新添加的用户 B 想要注册到该站点,而不是创建新用户,我想使用注册表单中提供的数据更改现有用户。
我想提一下,我还计划将 django-allauth 用于社交帐户用户。
我的问题(考虑到 Django 1.5)是如何使其工作的首选方式:
这是我应该创建自己的用户管理器还是应该研究身份验证后端?在这一点上我真的迷路了。
下图代表了两种情况,注册用户并将用户添加到组中:
更新:
所以我尝试了以下操作,创建了自定义用户模型,在 __new__ 方法中,如果相关对象已经存在并且 is_active 设置为 False,我将返回它。下面是 UserManager 和 user 模型:
class GruppuUserManager(BaseUserManager):
def create_user(self, username, email=None, password=None, phonenumber=None, **extra_fields):
now = timezone.now()
if not username:
raise ValueError('The given username must be set')
if not phonenumber:
raise ValueError('The given phonenumber must be set')
''' now lookup the user if it exists and is_active is set
then it is duplicate, otherwise return the user
and set the is_active to true '''
email = self.normalize_email(email)
if GruppUser.objects.filter(phonenumber__exact=phonenumber).exists():
if GruppUser.objects.filter(phonenumber__exact=phonenumber).values('is_active'):
''' duplicate - raise error '''
raise ValueError('The user is duplicate ')
else:
''' get the subscriber and set all the values '''
user = GruppUser.objects.filter(phonenumber__exact=phonenumber)
user.set_password(password)
user.is_active=True
if email:
user.email = email
user.save(using=self._db)
return user
user = self.model(username=username, email=email,
is_staff=False, is_active=True, is_superuser=False,
last_login=now, date_joined=now, phonenumber=phonenumber, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, username, email=None, password=None, phonenumber=None, **extra_fields):
u = self.create_user(username, email, password, phonenumber, **extra_fields)
u.is_staff = True
u.is_active = True
u.is_superuser = True
u.save(using=self._db)
return u
class GruppUser(AbstractBaseUser, PermissionsMixin):
''' django 1.5 - creating custom user model '''
id = models.AutoField(primary_key=True)
username = models.CharField(_('username'), max_length=30, unique=True,
help_text=_('Required. 30 characters or fewer. Letters, numbers and '
'@/./+/-/_ characters'),
validators=[
validators.RegexValidator(re.compile('^[\w.@+-]+$'), _('Enter a valid username.'), 'invalid')
])
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
email = models.EmailField(_('email address'), blank=True)
is_staff = models.BooleanField(_('staff status'), default=False,
help_text=_('Designates whether the user can log into this admin '
'site.'))
is_active = models.BooleanField(_('active'), default=True,
help_text=_('Designates whether this user should be treated as '
'active. Unselect this instead of deleting accounts.'))
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
phonenumber = models.CharField(max_length=10)
#following = models.ManyToManyField(Stream,blank=True,null=True)
blocked_con = models.ManyToManyField(Blocked_Content,blank=True,null=True)
mmsemail = models.EmailField(_('email address'), blank=True)
smsemail = models.EmailField(_('email address'), blank=True)
verified = models.BooleanField(_('verified'), default=False,
help_text=_('Defines if the user has been verified'))
objects = GruppuUserManager()
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['phonenumber']
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
def __init__(self,phone=None,*args, **kwargs):
''' save the phone number '''
super(GruppUser,self).__init__(*args, **kwargs)
self.phonetocheck = phone
@staticmethod
def __new__(cls,phone=None,*args, **kwargs):
''' lookup for the same user '''
if GruppUser.objects.filter(phonenumber__exact=phone).exists():
if self.objects.filter(phonenumber__exact=phone).values('is_active'):
''' duplicate - raise error '''
raise ValueError('The user is duplicate')
else:
''' get the subscriber and set all the values '''
user = self.objects.filter(phonenumber__exact=phone)
user.is_active = True
return user
return super(GruppUser,cls).__new__(cls,*args, **kwargs)
def get_full_name(self):
"""
Returns the first_name plus the last_name, with a space in between.
"""
full_name = '%s %s' % (self.first_name, self.last_name)
return full_name.strip()
def get_short_name(self):
"Returns the short name for the user."
return self.first_name
def email_user(self, subject, message, from_email=None):
"""
Sends an email to this User.
"""
send_mail(subject, message, from_email, [self.email])
无论如何,我现在遇到的奇怪问题是我无法连接到管理站点,这给了我以下错误:
我跟踪了 django,似乎查询集以某种方式向左移动:
(Pdb) context[self.user].phonenumber
u''
(Pdb) context[self.user].date_joined
u'9135261969'
(Pdb) context[self.user].is_active
datetime.datetime(2013, 9, 8, 20, 47, 30, tzinfo=<UTC>)
但是mysql中的数据是正确的:
mysql> select is_active from demo_app_gruppuser;
+-----------+
| is_active |
+-----------+
| 1 |
+-----------+
1 row in set (0.00 sec)
mysql> select phonenumber from demo_app_gruppuser;
+-------------+
| phonenumber |
+-------------+
| 9135261969 |
+-------------+
1 row in set (0.00 sec)
mysql> select date_joined from demo_app_gruppuser;
+---------------------+
| date_joined |
+---------------------+
| 2013-09-08 20:47:30 |
+---------------------+
1 row in set (0.00 sec)
这是尝试登录管理员时的回溯:
20. context[self.varname] = LogEntry.objects.filter(user__id__exact=user_id).select_related('content_type', 'user')[:int(self.limit)]
File "/usr/site/gruppe/lib/python2.7/site-packages/django/db/models/manager.py" in filter
155. return self.get_query_set().filter(*args, **kwargs)
File "/usr/site/gruppe/lib/python2.7/site-packages/django/db/models/query.py" in filter
667. return self._filter_or_exclude(False, *args, **kwargs)
File "/usr/site/gruppe/lib/python2.7/site-packages/django/db/models/query.py" in _filter_or_exclude
685. clone.query.add_q(Q(*args, **kwargs))
File "/usr/site/gruppe/lib/python2.7/site-packages/django/db/models/sql/query.py" in add_q
1259. can_reuse=used_aliases, force_having=force_having)
File "/usr/site/gruppe/lib/python2.7/site-packages/django/db/models/sql/query.py" in add_filter
1190. connector)
File "/usr/site/gruppe/lib/python2.7/site-packages/django/db/models/sql/where.py" in add
71. value = obj.prepare(lookup_type, value)
File "/usr/site/gruppe/lib/python2.7/site-packages/django/db/models/sql/where.py" in prepare
339. return self.field.get_prep_lookup(lookup_type, value)
File "/usr/site/gruppe/lib/python2.7/site-packages/django/db/models/fields/__init__.py" in get_prep_lookup
322. return self.get_prep_value(value)
File "/usr/site/gruppe/lib/python2.7/site-packages/django/db/models/fields/__init__.py" in get_prep_value
555. return int(value)
Exception Type: ValueError at /admin/
Exception Value: invalid literal for int() with base 10: 'root'
同样在 pdb 中有趣的是 self.user.id 在这种情况下应该是 1 正在返回“root”。似乎 django 以某种方式弄乱了我的 pk 在这个模型中的内容,即使我在模型中指定了它:
id = models.AutoField(primary_key=True)