instagram 만들기 (1)유저 지정 및 회원가입

2022. 4. 4. 01:31
  • 커스텀 유저생성(user model)
  • 아이디 / 암호 / 이메일 /이름을 받아서 회원가입 구현

1. Usermodel 생성

  • accounts app 생성
  • accounts app의 models.py에서 Usermodel을 생성
    • Abstractuser를 상속받았음 > AbstractUser에서 제공하는 필드들(first_name,last_name,email....)을 그대로 사용
#accounts/models.py
from django.db import models
from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    website_url = models.URLField(blank=True, max_length=200)
    bio = models.TextField(blank=True)
    phone_number = models.DecimalField(blank=True,max_digits=12,decimal_places=0)

 

2. AUTH_USER_MODEL 설정

  • 생성한 usermodel에 대해 AUTH_USER_MODEL 설정
    • 이 프로젝트 내부에서 돌리는 usermodel은 accounts.user라는 것임
#settings.py
AUTH_USER_MODEL = "accounts.User"

 

3. 회원가입을 정보를 담을 form 구현

  • 참고)form을 쓰는 이유 : https://han-py.tistory.com/87?category=907665 
    • 사용자가 정보를 적을 수 있게 form양식을 사용자에 주고
    • 사용자가 그 form에 제출한 정보를 담아 views에서 받고, db로 처리해줌
    • 즉 정보를 담는 통 역할을 함
  • forms.py에서 회원가입을 위한 정보를 담을 통인 signupform 구현
  • 비밀번호에 관한 로직(암호화, 비밀번호 확인)등을 위해 usercreationform을 사용
    • 참고로 usercreationform은 usermodel을 상속받는 모델폼임. 즉 usermodel기반의 modelform에 이런저런 기능등을 갖다 붙인 것임
  • __init__
    • 원래 설정된 기능이 정상작동 하도록 super사용
    • __super__.__init__ 하고나서야 filed값이 생겨서, 아래의 fields.required가 가능하다.
    • fileds.required 값을 필수로 수정하기 위해 사용
  • Meta : 모델폼에서 사용되는 장고 고유의 문법으로, form의 데이터 자체에 대해서 설정
    • 연동되는 모델 = get_user_model(). get_user_model()을 하면 현재 활성화된 모델을 가져올 수 있음
    • 모델의 데이터 필드들 중, 받을 데이터의 필드 = username~phone_number
  • clean_field
    • 참고(https://www.inflearn.com/questions/490676)
    • form.cleaned_data는 유효성 검사가 시작되는 시점에 빈 사전으로 초기화가 진행되며, 각 필드(폼에서 받는 데이터필드)에 대한 값들이 업데이트 됨
    • 유효성 검사 과정에서, 각 Form field별 유효성 검사를 수행한 후, form 인스턴스에 clean_필드명 이름의 속성이 있을 경우 이를 호출함
    • clean_필드명 함수의 반환값은 cleaned_data에 저장됨(즉 마치, 유효성검사후에 clean_field명 함수로 유효성검사를 한번 더 진행하는 것같은 느낌임)
    • 의문점)cleaned_data에는 필드별 모든 정보가 담기는 걸로 알고 있는데, clean_필드명 함수가 없다면 그냥 함수를 거치지 않고 바로 담기는지?
#accounts/forms.py
class SignupForm(UserCreationForm):
    def  __init__(self,*args,**kwargs):
        super().__init__(*args,**kwargs)
        #print(self.field['email'].required)
        self.fields['email'].required = True
        self.fields['first_name'].required = True
        self.fields['last_name'].required = True
        self.fields['phone_number'].required = True
    
    class Meta(UserCreationForm.Meta):
        #Meta도 usercreationform의 메타이기 때문
        model = get_user_model()
        #model도 직접적으로 설정을 해줘야 함. auth에 있는 모델에 의존하고 있기 때문
        fields = ['username','email','first_name','last_name','phone_number']


        #form이 제출될 때, clean_field형식의 함수들이 자동으로 호출이 됨? 
        #답변 form.cleaned_data는 유효성 검사가 시작되는 시점에 빈 사전으로 초기화가 되며, 유효성 검사 과정에서 각 필드에 대한 값들이 업데이트됨
    def clean_email(self):
        email = self.cleaned_data.get('email')
        if email:
            qs = User.objects.filter(email=email)
            if qs.exists():
                raise forms.ValidationError("이미 등록된 이메일 주소입니다.")
        return email

    def clean_phone_number(self):
        phone_number = self.cleaned_data.get('phone_number')
        if phone_number:
            qs = User.objects.filter(phone_number=phone_number)
            if qs.exists():
                raise forms.ValidationError("이미 등록된 전화번호 입니다")
        return phone_number

 

4. views.py

  • get으로 요청이 왔다 > 빈 signupform을 담은 html파일 랜더링 > 사용자가 정보 입력
  • 동일한 url로 post요청하면서 입력된 정보를 전달 > views에서 받아서, form객체에 해당 요청의 post메서드 값을 담음
    • form에 담겨져 오는게 아니라, 데이터를 받고 이때 form에 넣어주는 것임
    • 즉 처음에 보내주는 빈 signupform과 나중에 받는 데이터가 연결되어 있는게 아닌 듯함..
  • 데이터를 form에 담은 후, 각 데이터필드 별로 유효성 검사를 진행 > 문제가 없으면 form.save실행(db에 데이터 저장)
    • form인스턴스 하나가 db한줄이라고 생각하면 된다
  • url로 통해 들어오는 get값에서 next를 가져오고, next가 없으면 '/'를 가져와서 next_url로 받음
    • 원래 사용자가 접근하려 했던 경로가 존재할 경우(그러니까, 특정 접근 도중에 회원가입을 하라고 요청받을 경우) 원래 접근하려 했던 경로가 url에 next쿼리스트링 값으로 노출된다
    • ex) http://127.0.0.1:8000/accounts/signup/?next=article/4/update
    • 그리고 이 next의 쿼리스트링 값을, request.Get으로 접근할 수 있다. 참고로 어떤 메서드이든지 get요청에 대한 부분은 존재할 수 있다. url로 접근을 하기 때문임
    • 또한 request.GET은 querydict형태로, dict에서 사용가능한 get메소드 등을 사용할 수 있다.
    • 따라서 next_url = request.Get.get('next','/')로 받아줌. next가 존재하면 next string의 값을 받아서 원래 사용자가 가려했던 곳으로 다시가게 해주고 , 없으면 '/'으로 즉 root경로로(홈페이지로) 이동하게 됨
    • 만약 next값이 없다면 홈페이지('/')로 이동
      • 추가) '/'로 이동한다는 것은  'http://127.0.0.1:8000/' 로 이동을 한다는 것임
#accounts/views.py
def signup(request):
    if request.method == "POST":
        form = SignupForm(request.POST)
        if form.is_valid():
            form.save()
            messages.success(request,"회원가입을 환영합니다!")
            next_url = request.Get.get('next','/')
            #post메소드여도, url을 통해 들어오는 get값이 있음
            return redirect(next_url)
    else:
        form = SignupForm()
    return render(request,'accounts/signup_form.html',{
        'form':form,
    })

 

5 . html파일

  • html파일부분은 크게 다루지 않을 생각임. 다만 각 챕터별로 사용된 방법(?), 기술(?)에 대해서 적으려 함

 

message

  • 바로위에 views.py에 보면 messages에 관한 부분이 있음
  • 로그인 성공시 message 객체를 보내는 건데, message가 존재할 경우 다음과 같이 html파일에서 표시해주도록 할 수 있음
  • 이런식으로 짤 경우, message들이 div태그안에 담겨져서 보이게 되며, message들이 여러개라면 다같이 보이게 됨
    {% if messages %}
      {% for message in messages %}
        <div class = "alert alert-{{ messages.tag }}" >
          {{ message }}
        </div>
      {% endfor %}
    {% endif %}

 

extends와 include를 함께 사용

  • extends로 accounts/layout.html 파일을 땡겨와서(extend) 해당 파일안에 자신(signup_form.html)을 담음
  • 자신 안에는 _form.html을 들고와서 포함시킴(include)
    •  포함시킬 때, with를 사용해서 특정 변수(submit_label)에 대한 값을 주었음
#signup_form.html
{% extends 'accounts/layout.html' %} 
{% load bootstrap5 %} 

{% block content %}

<div class="container">
    <div class="row">
      <div class="col-sm-8 offset-sm-2">
          {% include "_form.html" with submit_label="회원가입" %}
      </div>
    </div>
  </div>

{% endblock %}
#_form.html
{% load bootstrap5 %}
        <form action="" method="POST" enctype="multipart/form-data">
          {% csrf_token %} {% bootstrap_form form %} {% buttons %}
          <button type="submit" class="btn btn-primary">
              {{ submit_label|default:"" }}
            </button>
          {% endbuttons %}
        </form>

 

추가로 해보고 싶은 것

  • form자체를 좀 이쁘게 (인스타그램처럼)꾸며보고 싶음. 하는 방법이 있는데 나중에 찾아볼 것
 

BELATED ARTICLES

more