0

ユーザーがグループを作成して写真を共有できる写真共有サイトをdjangoで構築しています。すべての要件をカバーする適切なユーザー データ モデル/ロジックの作成に問題があります。

基本的な要件は次のとおりです。

  • ユーザー A は、別のユーザー (ユーザー B) を追加できるグループを作成できます
  • グループに追加する必要があるユーザー B が既に存在する場合は、この既存のユーザー B を使用して、グループを表すグループ モデルの manytomany フィールドに追加します。
  • ユーザー B が存在しない場合は、一種の「ダミー」ユーザーを作成します。user_active を false に設定します。これは、ユーザー B がまだ検証やパスワードを設定していないためです。

新しく追加されたユーザー B をサイトに登録したい場合、新しいユーザーを作成する代わりに、サインアップ フォームから提供されたデータを使用して既存のユーザーを変更したいと思います。

ソーシャル アカウントのユーザーには django-allauth も使用する予定です。

私の質問(Django 1.5を考慮して)は、これを機能させるための好ましい方法は何ですか:

これは、独自のユーザー マネージャーを作成する必要がありますか、それとも認証バックエンドを調べる必要がありますか? この時点で本当に迷っています。


以下は、サインアップとグループへのユーザーの追加の両方のシナリオを表す図です。

http://i821.photobucket.com/albums/zz136/jorge_sanchez4/f79934d4-d0a4-4862-ab8b-7e1d09cd5642_zps06ec08f3.jpg


アップデート:

そこで、__new__ メソッドで、関連するオブジェクトが既に存在し、is_active が False に設定されている場合に、そのオブジェクトを返すカスタム ユーザー モデルを作成しました。以下は、UserManager とユーザー モデルの両方です。



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 で興味深いのは、この場合は 1 であるはずの self.user.id が「ルート」を返していることです。モデルで指定した場合でも、どういうわけか django がこのモデルにある私の pk を台無しにしたようです:

    id = models.AutoField(primary_key=True)
4

1 に答える 1

0

Django モデルで __new__ メソッドを使用することはお勧めできません。Model Manager の create_user を使用しても問題ありません。

于 2013-09-09T19:47:08.513 に答える