인프런 커뮤니티 질문&답변

김도하님의 프로필 이미지

작성한 질문수

파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트

Custom User 정보 views에서 request 값

작성

·

218

·

수정됨

0

안녕하세요.

커스텀 유저 모델을 만들어 잘 적용하였습니다.

템플릿 쪽에서는 로그인된 유저의 {{ user }} 형태로 접근하여 커스텀으로 만든 필드들의 값에 접근이 잘 됩니다.

views에서 request.user 를 할 경우, 커스텀 된 필드들의 값을 사용할 수 없고 기본 유저 모델의 필드값만 나오고 있습니다. 어떤 장치를 해주어야 커스텀 된 필드 값들을 모두 사용할 수 있는지 찾아보았지만 정확히 알아내지 못하였습니다...

 

임시로 request.user를 통해 현재 로그인 된 사용자 정보를 가져오고 커스텀 유저 모델에서 동일한 유저를 찾아서 정보를 사용하는 형태로 해두었는데, 좋은 방향이 아닌듯하여 도움을 얻고자 질문을 남기게 되었습니다.

 

def home(request):
    login_user = request.user
    user_site = User.objects.filter(email=login_user).get().site
    site_id = SiteInfo.objects.filter(site_name=user_site).get().pk
    boat_info = BoatInfo.objects.filter(site=site_id)

    return render(request, 'monitoring/home.html', {
        'boat_info': boat_info,
    })

 

번외로 템플릿에서 DB 데이터 갯수만큼만 DIV를 행렬로 만들어야 하는데, 짧은 지식으로 아래와 같이 구현해 보았습니다만, 좋은 방향으로 보이진 않아서 계속 고민 중에 있습니다. 한번 살펴봐 주시면 감사하겠습니다(꾸벅)

{% for boat in boat_info %}
    {% if forloop.counter0 != 0 and forloop.counter0|divisibleby:3 %}
    </div>
    {% endif %}
    {% if forloop.counter0|divisibleby:3 %}
    <div class="row">
    {% endif %}
        <div class="col">{{ boat }}}</div>
    {% if forloop.last %}
    </div>
    {% endif %}
{% endfor %}

답변 1

0

이진석님의 프로필 이미지
이진석
지식공유자

안녕하세요.

home 뷰에서 쓰신 User 모델은 직접 정의하신 모델이신거죠? settings.AUTH_USER_MODEL 설정과는 무관한 모델이 맞는 지요?

request.user 속성은 인증여부에 따라 settings.AUTH_USER_MODEL 에 지정된 모델(디폴트 값: "auth.User" => auth 앱의 User 모델)을 통해, 데이터베이스를 조회합니다.

모델의 이름만 User로 지정한다고 해서, 그 User 모델이 장고 프로젝트의 유저 모델로 활용되는 것은 아닙니다. 하나의 장고 프로젝트에는 다수의 장고 앱(app)이 있을 수 있고, 각 장고 앱마다 User라는 이름의 모델이 하나씩 존재할 수 있습니다. 그렇게 존재해도 문제되지 않습니다.


settings.AUTH_USER_MODEL에 명시된 모델이 아닌 그 외의 모델은 뷰 단에서 직접 조회해서, 템플릿의 context data로 넘겨서 처리하셔야 합니다. 쓰신 코드 처럼요.


그리고, 그리드 방식으로 레이아웃을 배치하고싶으신 듯 한데요. 이를 쉽게 도와주는 CSS가 있습니다. CSS Flex와 CSS Grid인데요. bootstrap4와 bootstrap5에서도 이를 도와주는 클래스가 있습니다.

아래 포스팅에 설명이 잘 되어있으니, 이 기회에 꼭 익혀보시길 추천드립니다.

위 포스팅대로 해보시고, bootstrap4의 flex, bootstrap5의 flex를 써보시는 것도 좋습니다.

살펴보시고, 추가 질문 댓글 남겨주세요.

화이팅입니다. :-)

김도하님의 프로필 이미지
김도하
질문자

레이아웃은 Grid 사용해서 쉽게 처리하였습니다!

말씀해주신 settings부분은

# settings.py

AUTH_USER_MODEL = 'accounts.User'

이렇게 세팅을 해둔 상태였습니다.

accounts 앱을 만들고, AbstractBaseUser, BaseUserManager 을 사용해서 커스텀유저를 만들어둔 상태입니다. 템플릿쪽에서는 별다른 처리없이 바로 user 오브젝트에 붙었을때 커스텀해둔 필드 값들이 바로 사용되어 지는데, 뷰 쪽에서는 request를 통한건 AUTH_USER_MODEL을 세팅해둔것과 상관없이 장고 기본 유저 모델로 밖에 연결이 안되는 건가요?

#accounsts/models.py

from django.db import models
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
from django.contrib.auth.validators import UnicodeUsernameValidator
from django.core.mail import send_mail
from django.utils.translation import gettext_lazy as _
from django.utils import timezone
from phonenumber_field.modelfields import PhoneNumberField


class UserManager(BaseUserManager):
    use_in_migrations = True

    def _create_user(self, username, email, password, **extra_fields):
        if not email:
            raise ValueError("Email을 입력해주세요.")

        email = self.normalize_email(email)
        username = self.model.normalize_username(username)
        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_manager', False)
        extra_fields.setdefault('is_superuser', False)

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

    def create_staff(self, username, email, password=None, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_manager', False)
        extra_fields.setdefault('is_superuser', False)

        if extra_fields.get('is_staff') is not True:
            raise ValueError('is_staff=True일 필요가 있습니다.')

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

    def create_manager(self, username, email, password=None, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_manager', True)
        extra_fields.setdefault('is_superuser', False)

        if extra_fields.get('is_staff') is not True:
            raise ValueError('is_staff=True일 필요가 있습니다.')
        if extra_fields.get('is_manager') is not True:
            raise ValueError('is_manager=True일 필요가 있습니다.')

        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_manager', True)
        extra_fields.setdefault('is_superuser', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError('is_staff=True일 필요가 있습니다.')
        if extra_fields.get('is_manager') is not True:
            raise ValueError('is_manager=True일 필요가 있습니다.')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('is_superuser=True일 필요가 있습니다.')

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


class User(AbstractBaseUser, PermissionsMixin):
    username_validator = UnicodeUsernameValidator()

    username = models.CharField(_("username"), max_length=50, validators=[username_validator])
    email = models.EmailField(_("email_address"), unique=True)
    contact = PhoneNumberField(_("contact"))
    address = models.CharField(_("address"), max_length=100)
    zipcode = models.CharField(_("zipcode"), max_length=6)
    site = models.CharField(_("site"), max_length=60)
    is_staff = models.BooleanField(_("staff_status"), default=False)
    is_manager = models.BooleanField(_("manager_status"), default=False)
    is_active = models.BooleanField(_("active"), default=True)
    date_joined = models.DateTimeField(_("date_joined"), default=timezone.now)
    created_at = models.DateTimeField(_("create"), auto_now_add=True)
    updated_at = models.DateTimeField(_("update"), auto_now=True)

    objects = UserManager()
    USERNAME_FIELD = "email"
    EMAIL_FIELD = "email"
    REQUIRED_FIELDS = ['username']

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

    def clean(self):
        super().clean()
        self.email = self.__class__.objects.normalize_email(self.email)

    def email_user(self, subject, message, from_email=None, **kwargs):
        send_mail(subject, message, from_email, [self.email], **kwargs)
김도하님의 프로필 이미지
김도하
질문자

views에서 사용할 때, request.user.site 에서 site 부분에 밑줄이 그어지고 request.user. 에서 바로 연동되는 곳에 안떠서 안되는거라 생각했는데 상관없이 그냥 넣어보니깐 잘 나오네요,,,,,,,,

이진석님의 프로필 이미지
이진석
지식공유자

@김도하 : IDE에서는 request.user 만으로는 타입 추론이 어렵기에 IDE에서 속성을 정확히 뽑아주기는 힘듭니다. user: User = request.user 처럼 Type Hinting을 지정하시고, user 객체를 통해 접근하시면 보다 원활히 타입의 혜택을 누리실 수 있습니다.