python Django自定义用户模型

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python Django自定义用户模型相关的知识,希望对你有一定的参考价值。

from django.conf import settings
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
from django.utils.translation import ugettext_lazy as _

# registerのUserモデルを使う場合だけ、登録する
if settings.AUTH_USER_MODEL == 'register.User':
    from .models import User

    class MyUserChangeForm(UserChangeForm):
        class Meta:
            model = User
            fields = '__all__'


    class MyUserCreationForm(UserCreationForm):
        class Meta:
            model = User
            # fields = ('email',)
            fields = ('username', 'email')


    class MyUserAdmin(UserAdmin):

        form = MyUserChangeForm
        add_form = MyUserCreationForm
        list_display = ('username', 'email', 'last_name', 'first_name', 'is_staff')
        list_filter = ('is_staff', 'is_superuser', 'is_active', 'groups')
        
        # search_fields = ('email', 'first_name', 'last_name')
        # ordering = ('email',)
        

    admin.site.register(User, MyUserAdmin)

# カスタムユーザーを使う
AUTH_USER_MODEL = 'register.User'
from django import forms
from django.contrib.auth.forms import (
    AuthenticationForm, UserCreationForm, PasswordChangeForm,
    PasswordResetForm, SetPasswordForm
)
from django.contrib.auth import get_user_model

from .models import UserProfile
import bootstrap_datepicker_plus as datetimepicker

User = get_user_model()


class LoginForm(AuthenticationForm):
    """ログインフォーム"""

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field in self.fields.values():
            field.widget.attrs['class'] = 'form-control'
            field.widget.attrs['placeholder'] = field.label  # placeholderにフィールドのラベルを入れる


class UserCreateForm(UserCreationForm):
    """ユーザー登録用フォーム"""

    class Meta:
        model = User
        if User.USERNAME_FIELD == 'email':
            fields = ('email',)
        else:
            fields = ('username', 'email')

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field in self.fields.values():
            field.widget.attrs['class'] = 'form-control'


class UserUpdateForm(forms.ModelForm):
    """ユーザー情報更新フォーム"""

    class Meta:
        model = User
        if User.USERNAME_FIELD == 'email':
            fields = ('email', 'last_name', 'first_name')
        else:
            fields = ('username', 'email', 'last_name', 'first_name')

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field in self.fields.values():
            field.widget.attrs['class'] = 'form-control'


class MyPasswordChangeForm(PasswordChangeForm):
    """パスワード変更フォーム"""

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field in self.fields.values():
            field.widget.attrs['class'] = 'form-control'


class MyPasswordResetForm(PasswordResetForm):
    """パスワード忘れたときのフォーム"""

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field in self.fields.values():
            field.widget.attrs['class'] = 'form-control'


class MySetPasswordForm(SetPasswordForm):
    """パスワード再設定用フォーム(パスワード忘れて再設定)"""

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field in self.fields.values():
            field.widget.attrs['class'] = 'form-control'



class InputProfileForm1(forms.Form):
    birth = forms.DecimalField(
        label = '生年月日(西暦)',
        required=True,
        widget = datetimepicker.DatePickerInput( # スマホ対応版 キーボード入力不可
            format = '%Y-%m-%d',
            attrs={'readonly': 'true'},
            options = {
                'locale':'ja',
                'dayViewHeaderFormat': 'YYYY年 MMMM',
                'ignoreReadonly': True,
                'allowInputToggle': True,
            }
        ),
    )

    height = forms.DecimalField(
        max_digits=4,
        decimal_places=1,
        max_value=220,
        min_value=100,
        label = '身長(cm)',
        required=True,
    )

class InputProfileForm(forms.ModelForm):
    """ユーザープロファイル更新フォーム"""

    class Meta:
        model = UserProfile
        fields = ('birth', 'height')

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field in self.fields.values():
            field.widget.attrs['class'] = 'form-control'
from django.conf import settings
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
from django.utils.translation import ugettext_lazy as _

# registerのUserモデルを使う場合だけ、登録する
if settings.AUTH_USER_MODEL == 'register.User':
    from .models import User

    class MyUserChangeForm(UserChangeForm):
        class Meta:
            model = User
            fields = '__all__'


    class MyUserCreationForm(UserCreationForm):
        class Meta:
            model = User
            # fields = ('email',)
            fields = ('username', 'email')


    class MyUserAdmin(UserAdmin):

        form = MyUserChangeForm
        add_form = MyUserCreationForm
        list_display = ('username', 'email', 'last_name', 'first_name', 'is_staff')
        list_filter = ('is_staff', 'is_superuser', 'is_active', 'groups')
        
        # search_fields = ('email', 'first_name', 'last_name')
        # ordering = ('email',)
        




    admin.site.register(User, MyUserAdmin)
from django.conf import settings
from django.db import models
from django.core.mail import send_mail
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.base_user import AbstractBaseUser
from django.utils.translation import ugettext_lazy as _ # 翻訳置換
from django.utils import timezone
from django.contrib.auth.base_user import BaseUserManager

# registerのUserモデルを使う場合だけ、登録する
if settings.AUTH_USER_MODEL == 'register.User':
    class UserManager(BaseUserManager):
        """ユーザーマネージャー"""
        use_in_migrations = True

        def _create_user(self, username, email, password, **extra_fields):
            """Create and save a user with the given username, email, and
            password."""
            if not username:
                raise ValueError('The given username must be set')

            if not email:
                raise ValueError('The given email must be set')
            email = self.normalize_email(email)

            user = self.model(username=username, email=email, **extra_fields)
            user.set_password(password)
            user.save(using=self._db)
            return user

        def create_user(self, username, email, password=None, **extra_fields):
            extra_fields.setdefault('is_staff', False)
            extra_fields.setdefault('is_superuser', False)
            return self._create_user(username, email, password, **extra_fields)

        def create_superuser(self, username, email, password, **extra_fields):
            extra_fields.setdefault('is_staff', True)
            extra_fields.setdefault('is_superuser', True)

            if extra_fields.get('is_staff') is not True:
                raise ValueError('Superuser must have is_staff=True.')
            if extra_fields.get('is_superuser') is not True:
                raise ValueError('Superuser must have is_superuser=True.')

            return self._create_user(username, email, password, **extra_fields)


    class User(AbstractBaseUser, PermissionsMixin):
        """カスタムユーザーモデル

        usernameを使わず、emailアドレスをユーザー名として使うようにしています。
        ⇒ username再追加(デフォルトUserクラスと同じ)
        """
        username = models.CharField(_('username'), max_length=30, unique=True)
        email = models.EmailField(_('email address'), unique=True)
        last_name = models.CharField(_('last name'), max_length=150, blank=True)
        first_name = models.CharField(_('first name'), max_length=30, 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)

        objects = UserManager()

        EMAIL_FIELD = 'email'
        USERNAME_FIELD = 'username'
        REQUIRED_FIELDS = ['email']

        class Meta:
            verbose_name = _('user')
            verbose_name_plural = _('users')

        def get_full_name(self):
            """Return 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):
            """Return the short name for the user."""
            return self.first_name

        def email_user(self, subject, message, from_email=None, **kwargs):
            """Send an email to this user."""
            send_mail(subject, message, from_email, [self.email], **kwargs)

        #@property
        #def username(self):
        #    return self.email




# ユーザーの追加情報 1:1レコード
class UserProfile(models.Model):
    owner = models.OneToOneField(User, on_delete=models.CASCADE, related_name='prifile_owner')

    birth = models.DateField(
        _('birth'),
        # verbose_name = '誕生日',
        help_text ='生年月日。例 1970-04-01',
    )  # 生年月日

    height = models.DecimalField(
        _('height'),
        max_digits=4,
        decimal_places=1,
        # verbose_name = '身長',
        help_text ='身長をcm単位で。例 155.3',    
    )  # 身長(cm)


from django.urls import path
from . import views
from django.views.generic import RedirectView

app_name = 'register'

urlpatterns = [
    path('', views.Top.as_view(), name='top'),
    #path('', RedirectView.as_view(url='/register/login')), 

    path('login/', views.Login.as_view(), name='login'),
    # path('logout/', RedirectView.as_view(url='/register/login'), name='logout'), 
    path('logout/', views.Logout.as_view(), name='logout'),

    path('user_create/', views.UserCreate.as_view(), name='user_create'),
    path('user_create/done/', views.UserCreateDone.as_view(), name='user_create_done'),
    path('user_create/complete/<token>/', views.UserCreateComplete.as_view(), name='user_create_complete'), #本登録用URL(<token>)
    path('user_detail/<int:pk>/', views.UserDetail.as_view(), name='user_detail'),
    path('user_update/<int:pk>/', views.UserUpdate.as_view(), name='user_update'),
    path('password_change/', views.PasswordChange.as_view(), name='password_change'),
    path('password_change/done/', views.PasswordChangeDone.as_view(), name='password_change_done'),
    path('password_reset/', views.PasswordReset.as_view(), name='password_reset'),
    path('password_reset/done/', views.PasswordResetDone.as_view(), name='password_reset_done'),
    path('password_reset/confirm/<uidb64>/<token>/', views.PasswordResetConfirm.as_view(), name='password_reset_confirm'),
    path('password_reset/complete/', views.PasswordResetComplete.as_view(), name='password_reset_complete'),
]
from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib.auth.views import (
    LoginView, LogoutView, PasswordChangeView, PasswordChangeDoneView,
    PasswordResetView, PasswordResetDoneView, PasswordResetConfirmView, PasswordResetCompleteView
)
from django.contrib.sites.shortcuts import get_current_site
from django.core.signing import BadSignature, SignatureExpired, loads, dumps
from django.http import HttpResponseBadRequest
from django.shortcuts import redirect, resolve_url
from django.template.loader import get_template
from django.urls import reverse_lazy
from django.utils import timezone
from django.views import generic
from .forms import (
    LoginForm, UserCreateForm, UserUpdateForm, MyPasswordChangeForm,
    MyPasswordResetForm, MySetPasswordForm,
    InputProfileForm,
)

from ap01diet.models import UserProfile

User = get_user_model()


class Top(generic.TemplateView):
    template_name = 'register/top.html'


class Login(LoginView):
    """ログインページ"""
    form_class = LoginForm
    template_name = 'register/login.html'


class Logout(LoginRequiredMixin, LogoutView):
    """ログアウトページ"""
    template_name = 'register/top.html'


class UserCreate(generic.CreateView):
    """ユーザー仮登録"""
    template_name = 'register/user_create.html'
    form_class = UserCreateForm

    def form_valid(self, form):
        """仮登録と本登録用メールの発行."""
        # 仮登録と本登録の切り替えは、is_active属性を使うと簡単です。
        # 退会処理も、is_activeをFalseにするだけにしておくと捗ります。
        user = form.save(commit=False)
        user.is_active = False
        user.save()

        # アクティベーションURLの送付
        current_site = get_current_site(self.request)
        domain = current_site.domain
        context = {
            'protocol': 'https' if self.request.is_secure() else 'http',
            'domain': domain,
            'token': dumps(user.pk),
            'user': user,
        }

        subject_template = get_template('register/mail_template/create/subject.txt')
        subject = subject_template.render(context)

        message_template = get_template('register/mail_template/create/message.txt')
        message = message_template.render(context)

        user.email_user(subject, message)
        return redirect('register:user_create_done')


class UserCreateDone(generic.TemplateView):
    """ユーザー仮登録したよ"""
    template_name = 'register/user_create_done.html'


class UserCreateComplete(generic.TemplateView):
    """メール内URLアクセス後のユーザー本登録"""
    template_name = 'register/user_create_complete.html'
    timeout_seconds = getattr(settings, 'ACTIVATION_TIMEOUT_SECONDS', 60*60*24)  # デフォルトでは1日以内

    def get(self, request, **kwargs):
        """tokenが正しければ本登録."""
        token = kwargs.get('token')
        try:
            user_pk = loads(token, max_age=self.timeout_seconds)

        # 期限切れ
        except SignatureExpired:
            return HttpResponseBadRequest()

        # tokenが間違っている
        except BadSignature:
            return HttpResponseBadRequest()

        # tokenは問題なし
        else:
            try:
                user = User.objects.get(pk=user_pk)
            except User.DoenNotExist:
                return HttpResponseBadRequest()
            else:
                if not user.is_active:
                    # まだ仮登録で、他に問題なければ本登録とする
                    user.is_active = True
                    user.save()
                    return super().get(request, **kwargs)

        return HttpResponseBadRequest()


class OnlyYouMixin(UserPassesTestMixin):
    """本人か、スーパーユーザーだけユーザーページアクセスを許可する"""
    raise_exception = True

    def test_func(self):
        user = self.request.user
        return user.pk == self.kwargs['pk'] or user.is_superuser


class UserDetail(OnlyYouMixin, generic.DetailView):
    """ユーザーの詳細ページ"""
    model = User
    template_name = 'register/user_detail.html'  # デフォルトユーザーを使う場合に備え、きちんとtemplate名を書く

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        pk = self.kwargs['pk']
        me = User.objects.get(id=pk)
        if  UserProfile.objects.filter(owner=me).exists():
            context['prof']  = UserProfile.objects.filter(owner=me)[0]
        else:
            context['prof']  = None
        
        return context


class UserUpdate(OnlyYouMixin, generic.UpdateView):
    """ユーザー情報更新ページ"""
    model = User
    form_class = UserUpdateForm
    template_name = 'register/user_form.html'  # デフォルトユーザーを使う場合に備え、きちんとtemplate名を書く

    def get_success_url(self):
        return resolve_url('register:user_detail', pk=self.kwargs['pk'])

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        pk = self.kwargs['pk']
        # me = User.objects.filter(id=pk)
        if  UserProfile.objects.filter(id=pk).exists():
            myprof = UserProfile.objects.filter(id=pk)[0]
            initial={
                # 'date':myobj0.date,
                'birth':myprof.birth,
                'height':myprof.height,
                }
        else:
            initial={
                'birth': "1970-01-01",
                'height':150.0,
            }


        context['form_parof'] = InputProfileForm(
            initial = initial
        )
        
        return context

    def post(self, request, *args, **kwargs):
        
        # User DBの更新
        super().post(request, *args, **kwargs)

        # Profile DBの更新
        pk = self.kwargs['pk']
        d = UserProfile.objects.filter(id=pk)[0]
        d.updated_by = self.request.user
        d.updated_at = timezone.now()
        d.height = request.POST['height']
        d.birth = request.POST['birth']
        d.save()
        
        return redirect('register:user_detail', pk=self.kwargs['pk'])


class PasswordChange(PasswordChangeView):
    """パスワード変更ビュー"""
    form_class = MyPasswordChangeForm
    success_url = reverse_lazy('register:password_change_done')
    template_name = 'register/password_change.html'


class PasswordChangeDone(PasswordChangeDoneView):
    """パスワード変更しました"""
    template_name = 'register/password_change_done.html'


class PasswordReset(PasswordResetView):
    """パスワード変更用URLの送付ページ"""
    subject_template_name = 'register/mail_template/password_reset/subject.txt'
    email_template_name = 'register/mail_template/password_reset/message.txt'
    template_name = 'register/password_reset_form.html'
    form_class = MyPasswordResetForm
    success_url = reverse_lazy('register:password_reset_done')


class PasswordResetDone(PasswordResetDoneView):
    """パスワード変更用URLを送りましたページ"""
    template_name = 'register/password_reset_done.html'


class PasswordResetConfirm(PasswordResetConfirmView):
    """新パスワード入力ページ"""
    form_class = MySetPasswordForm
    success_url = reverse_lazy('register:password_reset_complete')
    template_name = 'register/password_reset_confirm.html'


class PasswordResetComplete(PasswordResetCompleteView):
    """新パスワード設定しましたページ"""
    template_name = 'register/password_reset_complete.html'

以上是关于python Django自定义用户模型的主要内容,如果未能解决你的问题,请参考以下文章

无法使用用户名/密码登录令牌端点:drf 令牌身份验证和自定义用户模型,Django

Django 重写用户模型

从 django 用户模型迁移到自定义用户模型

django 自定义用户模型组和权限

Python/Django:添加自定义模型方法?

切换到 Django 自定义用户模型、组和权限