터칭 데이터

장고(Django) User 추가하기 본문

장고 (Django)

장고(Django) User 추가하기

터칭 데이터 2023. 11. 5. 00:58

Question 모델에 작성자 필드를 추가하고 자신이 작성한 질문만 수정할 수 있도록 하는 기능을 만들며 장고에서 제공하는 사용자 관리 기능에 대해서도 알아볼 것입니다.

 

 

 

 

 

django.contrib.auth에 대해

 

 

`django.contrib.auth`는 Django의 내장 인증 및 사용자 관리 앱입니다. 이 앱은 사용자 계정, 그룹, 권한 및 다른 인증 관련 기능을 구현하기 위한 모든 핵심 도구와 클래스를 제공합니다. 아래는 `django.contrib.auth`의 몇 가지 중요한 요소에 대한 간단한 설명입니다:

1. **User 모델**: `User` 모델은 사용자 계정을 나타내는 클래스로, 사용자 이름, 비밀번호, 이메일 등과 같은 필드를 가지고 있습니다. Django에서 내장된 User 모델을 사용하거나 커스텀 User 모델을 정의하여 사용할 수 있습니다.

2. **그룹(Group)**: 그룹은 사용자에 대한 권한을 그룹화하고 할당하는 데 사용됩니다. 그룹을 생성하고 사용자를 그룹에 추가하여 권한을 일괄 부여할 수 있습니다.

3. **권한(Permission)**: 권한은 특정 작업 또는 리소스에 대한 권한을 정의하는데 사용됩니다. 사용자나 그룹에게 권한을 할당하여 접근 제어를 설정할 수 있습니다.

4. **로그인 및 로그아웃 뷰**: `LoginView`와 `LogoutView` 등의 뷰 클래스를 제공하여 사용자 로그인 및 로그아웃을 처리할 수 있습니다.

5. **데코레이터 및 믹스인**: `@login_required` 데코레이터와 `UserPassesTestMixin` 등의 클래스를 사용하여 뷰에 인증 및 권한 검사를 추가할 수 있습니다.

6. **회원가입(Views 및 Forms)**: 회원가입 페이지를 구현하는 데 사용할 수 있는 뷰와 폼이 포함되어 있습니다.

7. **비밀번호 재설정 및 변경**: 비밀번호 재설정 및 변경을 처리하는 기능을 제공합니다. `PasswordResetView`, `PasswordResetConfirmView`, `PasswordChangeView` 등의 뷰를 사용할 수 있습니다.

8. **사용자 세션 관리**: 사용자의 세션 관리와 로그인 상태를 확인하는 기능을 제공합니다.

`django.contrib.auth` 앱을 사용하면 Django 애플리케이션에서 사용자 관리 및 인증을 간단하게 구현할 수 있습니다. 이를 통해 사용자 계정, 권한, 그룹, 로그인, 로그아웃, 비밀번호 관리 등을 손쉽게 처리할 수 있습니다.

 

 

 

 

 

우리는 이미 django.contrib.auth를 사용하고 있었습니다.

 

mysite/settings.py를 살펴보면

 

위와 같이 admin과 auth 코드가 있는데 우리가 프로젝트를 만들 때 같이 자동 생성된 기능들입니다.

admin 덕에 어드민 페이지를 이용할 수 있었고 auth 덕분에 superuser를 만들고 어드민 페이지에 로그인할 수 있었습니다.

 

Django는 기본적으로 django.contrib.auth 앱을 통해 회원관리를 할 수 있는 기능을 제공하는데, auth의 User 모델을 통해 여러 인증을 구현할 수 있다.

class models.User에서 이 User 모델을 사용해 장고 어드민 뿐만 아니라 일반 서비스에도 로그인 기능을 사용할 수 있습니다.

 

 

 

 

>>> from django.contrib.auth.models import User
>>> User._meta.get_fields()
(<ManyToOneRel: admin.logentry>, 
<django.db.models.fields.AutoField: id>, 
<django.db.models.fields.CharField: password>, 
<django.db.models.fields.DateTimeField: last_login>, 
<django.db.models.fields.BooleanField: is_superuser>, 
<django.db.models.fields.CharField: username>, 
<django.db.models.fields.CharField: first_name>, 
<django.db.models.fields.CharField: last_name>, 
<django.db.models.fields.EmailField: email>, 
<django.db.models.fields.BooleanField: is_staff>, 
<django.db.models.fields.BooleanField: is_active>, 
<django.db.models.fields.DateTimeField: date_joined>, 
<django.db.models.fields.related.ManyToManyField: groups>, 
<django.db.models.fields.related.ManyToManyField: user_permissions>)

>>> User.objects.all()
<QuerySet [<User: admin>, <User: admin2>]>

 

 

User 모델을 import하고 어떻게 구성됐는지 쉘에서 살펴봤습니다.

필드 하나하나가 전부 로그인 서비스에 관련된 기능들입니다. 지금까지 만들어진 User는 지난 시간 어드민 페이지 실습 때 만들었던 아이디 2개가 전부입니다.

 

이 User 기능을 Question 모델에 추가해 사용해보겠습니다.

 

 

 

 

 

 

 

 

 

모델에 User 모델을 이용해 owner 필드 추가하기

 

 

우리는 Question 모델에 새로운 필드인 owner를 추가했습니다.

 

`owner` 필드에 대한 설명은 다음과 같습니다:

1. `'auth.User'`:
   - `owner` 필드가 `auth.User` 모델과 연결됨을 나타냅니다. 이 필드는 사용자와 질문(Question) 모델 간의 관계를 정의합니다.

2. `related_name='questions'`:
   - 이 매개변수는 역참조 이름(related name)을 설정합니다. 사용자 모델에서 해당 사용자와 관련된 질문을 쉽게 가져오기 위한 역참조 이름입니다. 즉, `User` 모델 객체에서 해당 사용자와 연결된 질문을 가져올 때 `questions`라는 역참조 이름을 사용할 수 있습니다.

 

사람 한명이 질문을 여러개 작성할 수는 있지만, 질문 하나를 여러 사람이 작성했을리는 없기 때문에 질문자(owner)가 작성해 온 질문'들'을 찾을 때는 역참조가 됩니다. 정참조와 역참조가 헷갈린다면 여기를 참고하세요.

3. `on_delete=models.CASCADE`:
   - 이 매개변수는 연결된 사용자가 삭제될 때 어떻게 처리할지를 정의합니다. `models.CASCADE`는 사용자가 삭제되면 해당 사용자와 연결된 질문 역시 삭제됨을 의미합니다. 다시 말해, 사용자와 질문 간의 관계는 Cascade(연쇄) 삭제를 따릅니다.

4. `null=True`:
   - 이 매개변수는 해당 필드에 null 값을 허용할지를 지정합니다. `null=True`로 설정되어 있으므로, `owner` 필드는 null 값을 가질 수 있습니다. 이는 질문에 소유자(사용자)가 없는 경우를 나타내며, 사용자가 로그인하지 않은 경우와 같이 사용자 정보가 없을 때 유용합니다.

즉, 위의 코드는 `Question` 모델과 `User` 모델 간의 관계를 정의하며, 각 질문은 특정 사용자(소유자)와 연결됩니다. 질문과 사용자 간의 관계를 통해 질문 소유자와 질문을 쉽게 관리하고, 소유자가 삭제될 때 관련된 질문도 삭제되도록 설정합니다. 또한, `null=True` 설정을 통해 질문이 소유자 없이도 존재할 수 있음을 나타냅니다.

 

 

 

 

 

 

모델을 만들거나 변경하면 마이그레이션(migrations)

 

지난 시간 모델을 처음 배울 때 모델을 처음 만들거나 모델의 필드 등을 수정해 모델이 변경되었다면 쉘에서 이를 반영하기 위해 마이그레이션을 해야 한다고 배웠습니다. 기억 하시죠?

 

# makemigrations
(DjangoProjects) (..생략..)\mysite>python manage.py makemigrations
Migrations for 'polls':
  polls\migrations\0002_question_owner_alter_question_pub_date.py
    - Add field owner to question
    - Alter field pub_date on question



# migrate
(DjangoProjects) (..생략..)\mysite>python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
  Applying polls.0002_question_owner_alter_question_pub_date... OK

 

 

 

 

장고 쉘에서 유저가 작성한 question들을 가져오도록 해보겠습니다.

>>> from django.contrib.auth.models import User
>>> from polls.models import *

>>> user = User.objects.first()
>>> user.questions.all()
<QuerySet []>

 

맨 아래 그동안 작성한 question이 아무 것도 없다는 것은 쉽게 이해할 수 있습니다. 왜냐하면 우리는 그동안 만든 admin 유저로 question을 작성한 적이 없기 때문입니다. (question 작성자 필드인 owner를 모델에 방금 막 작성했기도 했고요!)

 

그런데 맨 아래에서 두번째 줄 user.questions.all()을 자세히 봐주세요. 뭔가 조금 어색하지 않나요? 그렇습니다. 우리는 하나의 question에 딸린 여러개의 choice들을 조회할 때는 question.choice_set.all()과 같이 (소문자로 표시된 역참조 모델이름)_set 을 사용했었는데 이번에는 하나의 user에 딸린 여러개의 question들을 조회하는데도 user.question_set.all()이 아닌 user.questions.all()을 사용했고 에러 없이 쿼리셋 조회가 정상적으로 진행됐습니다.

 

이 이유는 우리가 Question 클래스에서 models.ForeignKey에서 related_name을 'questions'로 지정했기 때문입니다.

related_name은 역참조를 할 때 대신 사용할 이름(명령)을 정의할 수 있으며 related_name을 정의하지 않으면 우리가 question으로 여러 choice를 진행할 때 처럼 (소문자역참조모델명)언더바.필터함수 로 사용해야 합니다.