1. Model (user)

- 기존 user에서 필드를 추가해주고 싶어서 AbstractUser를 상속해주었다!

  - 단, settings에서 따로 설정해줄 것 :

# 커스텀 유저 모델을 생성하기 위한 셋팅
AUTH_USER_MODEL = 'member.User'

- 처음에 추가한 필드 : 소개, 프로필 사진, 전화번호, 생일, 웹사이트

- 이후 기능구현을 위해 추가한 필드 : 팔로워, 사진 갯수

  - followers : 팔로우 기능을 구현하기 위해 ManyToManyField를 이용함.

from django.conf import settings
from django.contrib.auth.models import AbstractUser
from django.db import models

# User : 기본 user를 상속하여 추가 field로 구성
# cf. blank=True :빈 채로 저장 & null=True : null 값으로 저장


class User(AbstractUser):

    bio = models.TextField(null=True, blank=True) # 소개
    photo = models.ImageField(upload_to='user/%Y/%m/%d', null=True, blank=True) # 프로필 사진
    phone_number = models.CharField(null= True, blank=True, max_length=20) # 전화번호
    date_of_birth = models.DateField(null=True, blank=True) # 생일
    website = models.CharField(null=True, blank=True, max_length=100) # 웹사이트
    followers = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='followings') # follow 기능을 위해 추가함.
    # ManyToManyField -> related_name : 정참조하고 있는 클래스의 인스턴스에서 거꾸로 호출(역참조 할지를 정해주는 이름)
    photo_cnt = models.IntegerField(default=0)

2. URLs

- view와 template을 이어주는 역할!

from django.conf.urls import url
from django.urls import path
from . import views
from django.conf.urls.static import static
from django.conf import settings

urlpatterns = [
    url('join/', views.create_user, name="join"),
    url('login/', views.sign_in, name="login"),
    url('logout/', views.sign_out, name='logout'),
    url('delete/',views.delete, name='delete'),
    url('change_password/',views.change_password,name='change_password'),
    url('profile_update/',views.profile_update, name='profile_update'),
    path('people/<str:username>/', views.peoplePage , name="people"),
    path('follow/<str:username>/',views.follow, name='follow'),
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

3. View

- 각 함수마다 기능 해당하는 url의 기능 수행

# 절대 경로 설정을 위해 추가
import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(os.path.dirname(__file__))))
from photo.models import Photo

from django.db.models import Q
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login, logout, update_session_auth_hash, get_user_model
from django.contrib.auth.forms import AuthenticationForm, PasswordChangeForm
from django.views.generic import ListView
from rest_framework.generics import get_object_or_404

from .forms import UserCreationForm, ProfileForm
from .models import User

def change_password(request):
    if request.method == "POST":
        form = PasswordChangeForm(request.user, request.POST)
        if form.is_valid():
            user = form.save()
            update_session_auth_hash(request, user)
            messages.success(request, '패스워드가 성공적으로 업데이트 되었습니다.')
            return redirect('index') # 다음 url로 이동한다.
        else:
            messages.error(request,"다음 에러를 확인해주세요.")
    else:
        form = PasswordChangeForm(request.user)
    return render(request, 'registration/change_password.html',{'form':form})

# 계정 삭제 기능
def delete(request):
    if request.method == "POST":
        request.user.delete()
        return redirect('index')
    else:
        return render(request, 'registration/delete.html')



# New User Registration(회원가입 기능)
def create_user(request):
    if request.method == 'POST':
        try:
            username = request.POST['username']
            email = request.POST['email']
            password = request.POST['password1']
            new_user = User.objects.create_user(username, email, password)
            new_user.save()
            return render(request, 'registration/signup_done.html', {'message': '회원가입이 완료되었습니다.'})
        except:
            return render(request, 'registration/signup_done.html', {'message': '회원이 이미 있음'})
    else:
        form = UserCreationForm()
        return render(request, 'registration/signup.html', {'form': form})


# 로그아웃 기능
def sign_out(request):
    logout(request)
    return render(request, 'home/base.html')

# 로그인 기능
def sign_in(request):
    if request.method == 'POST':
        # 유저 (username, password)로 인증
        user = authenticate(request, username=request.POST.get('username', ''),
                            password=request.POST.get('password', ''))
        if user is not None:
            login(request, user) 
            return render(request, 'registration/signup_done.html', {'message': "로그인 되었습니다."})
        else:
            return render(request, 'registration/signup_done.html', {'message': "로그인에 실패하였습니다."})
    else:
        # 로그인 폼 생성
        form = AuthenticationForm()
        return render(request, 'registration/login.html', {'form': form})
        
# profile update
def profile_update(request):
    user = request.user
    if request.method == 'POST':
        profile_form = ProfileForm(request.POST, request.FILES, instance=user)
        if profile_form.is_valid(): # 단, form이 valid하지 않으면 저장되지 않는다. (예) 생일의 형식이 안맞을 때
            profile_form.save()
        return redirect('people', request.user.username)
    else:
        profile_form = ProfileForm(instance=user)
    return render(request, 'profile/profile_update.html', {'profile_form': profile_form})



# 게시물의 작성자의 username을 통해 user 페이지에 접근하기
def peoplePage(request,username):
    person = get_object_or_404(User, username=username)
    # 작성자가 username인 photo를 전달하기
    photo_list = Photo.objects.filter(Q(user=person))
    context={}
    context['people']=person
    context['object_list']= photo_list

    return render(request, "profile/people.html",context)

# 팔로우 기능 
def follow(request, username):
    people = get_object_or_404(get_user_model(), username=username)
    if request.user in people.followers.all():
        # people을 unfollow하기
        people.followers.remove(request.user)
    else:
        # people을 follow하기
        people.followers.add(request.user)
    return render(request, "profile/people.html",{'people': people})


WRITTEN BY
choco-songyi

,