Django

Django 기초 3주차_Sparta Coding Club

끈끈 2023. 4. 5. 10:41

 

3주차에서 배울 것

  • Django에서 제공하는 사용자 관리 기능 사용해 보기
  • Django에서 제공하는 사용자 모델 확장하기
  • 포스트 읽기 / 쓰기 / 삭제

 


 

Django의 사용자 모델 비교

 

auth_user
my_user

 

auth_user는 장고에서 미리 생성해 준 데이터베이스 테이블

my_user는 우리가 ORM을 사용해 만든 데이터베이스 테이블

 

auth_user에 내용을 훨씬 많이 담을 수 있지만 bio가 없다

고로 두 테이블을 합치면 두가지 장점 모두 사용 가능!

 

User모델 업그레이드 하기

 

user/models.py:

from django.db import models
from django.contrib.auth.models import AbstractUser # 장고에서 사용하는 기본 유저모델

class UserModel(AbstractUser): # 상속
    class Meta:
        db_table = "my_user"

    bio = models.CharField(max_length=256, default='') # 추가

 

mySpartaSns/settings.py:

AUTH_USER_MODEL = 'user.UserModel'

 

# User모델을 데이터베이스에 적용시키기
python manage.py makemigrations
python manage.py migrate

 

 

my_user

 

회원가입 기능 수정하기

 

user/views.py:

from django.shortcuts import render, redirect
from .models import UserModel
from django.http import HttpResponse
from django.contrib.auth import get_user_model # 사용자가 데이터베이스 안에 있는지 검사

def sign_up_view(request):
    if request.method == 'GET':
        return render(request, 'user/signup.html')
    elif request.method == 'POST':
        username = request.POST.get('username', None)
        password = request.POST.get('password', None)
        password2 = request.POST.get('password2', None)
        bio = request.POST.get('bio', None)

        if password != password2:
            return render(request, 'user/signup.html')
        else:
            exist_user = get_user_model().objects.filter(username=username) #####

            if exist_user:
                return render(request, 'user/signup.html')
            else:
                UserModel.objects.create_user(username=username, password=password, bio=bio) #####
                return redirect('/sign-in')

 

로그인 기능 수정하기

 

user/views.py:

from django.shortcuts import render, redirect
from .models import UserModel
from django.http import HttpResponse
from django.contrib.auth import get_user_model
from django.contrib import auth #####

def sign_in_view(request):
    if request.method == 'POST':
        username = request.POST.get('username', None)
        password = request.POST.get('password', None)

        me = auth.authenticate(request, username=username, password=password) #####
        if me is not None: # 저장된 사용자가 존재한다면
            auth.login(request, me)
            return HttpResponse(me.username + "님의 로그인 성공! 환영합니다!")
        else:
            return redirect('/sign-in')

    elif request.method == 'GET':
        return render(request, 'user/signin.html')

 


 

로그인 후 페이지 이동하기

 

페이지 연결시 views.py에 render() 함수를 사용,

작성한 views.py 함수를 urls.py에 연결.

 

tweet/views.py:

from django.shortcuts import render, redirect

def home(request):
    user = request.user.is_authenticated # 사용자의 로그인 확인
    if user:
        return redirect('/tweet')
    else:
        return redirect('/sign-in')

def tweet(request):
    if request.method == 'GET':
        return render(request, 'tweet/home.html')

 

tweet/urls.py:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.home, name='home'), # 127.0.0.1:8000 과 views.py 폴더의 home 함수 연결
    path('tweet/', views.tweet, name='tweet') # 127.0.0.1:8000/tweet 과 views.py 폴더의 tweet 함수 연결
]

 

django에게 알려줘야 함

 

mySpartaSns/urls.py:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('user.urls')),
    path('', include('tweet.urls')), # 추가
]

 

user/views.py:

def sign_in_view(request):
    if request.method == 'POST':
        username = request.POST.get('username', None)
        password = request.POST.get('password', None)

        me = auth.authenticate(request, username=username, password=password)
        if me is not None:
            auth.login(request, me)
            return redirect('/') # 로그인하면 홈으로 가도록 수정
        else:
            return redirect('/sign-in')

    elif request.method == 'GET':
        return render(request, 'user/signin.html')

 

/tweet/

 


 

로그인 이후 기능 다듬기

 

 

templates/tweet/home.html:

<h5 class="card-title">{{ user.username }}</h5>
<p class="card-text">{{ user.bio }}</p>

 

templates/base.html:

<form class="">
    {% if not user.is_authenticated %}
    # user가 로그인되어 있지 않을 때만 Sign In, Up을 보여주겠다
    # {% %} : 파이썬처럼 if문, for문 등을 작성할 수 있다
        <ul class="">
            ...
        </ul>
    {% else %}
        {{ user.username }} 님 반갑습니다! # 중괄호 두번으로 user의 정보 사용 가능(django)
    {% endif %}
</form>

 

로그인 한 사람은 사용 안 해도 되는 페이지

 

user = request.user.is_authenticated
if user:
    return redirect('/')
else:
    return render(request, 'user/signin.html')

 

로그아웃 구현하기

 

user/views.py:

from django.contrib.auth.decorators import login_required

@login_required # 로그인 한 사용자만 접근할 수 있게 해주는 기능
def logout(request):
    auth.logout(request)
    return redirect('/')

 

user/views.py:

from django.urls import path
from . import views

urlpatterns = [
    path('sign-up/', views.sign_up_view, name='sign-up'),
    path('sign-in/', views.sign_in_view, name='sign-in'),
    path('logout/', views.logout, name='logout'), # 추가
]

 

base.html:

{% else %}
    <ul class="navbar-nav mr-auto">
        <li class="nav-item disabled">
            <span class="nav-link">
                {{ user.username }} 님 반갑습니다!
            </span>
        </li>
        <li class="nav-item active">
            <a class="nav-link" href="/logout"> Logout <span class="sr-only"></span></a>
        </li>
    </ul>
{% endif %}

 

/tweet/ : Logout

 


 

게시글 쓰기

 

templates/tweet/home.html:

<form action="/tweet/" method="POST">
	{% csrf_token %}

 

tweet/views.py:

from django.shortcuts import render, redirect
from .models import TweetModel # 글쓰기 모델

def home(request):
    user = request.user.is_authenticated # 사용자의 로그인 확인
    if user:
        return redirect('/tweet')
    else:
        return redirect('/sign-in')

def tweet(request):
    if request.method == 'GET':
        user = request.user.is_authenticated  # 사용자의 로그인 확인
        if user:
            return render(request, 'tweet/home.html')
        else:
            return redirect('/sign-in')
    elif request.method == 'POST':
        user = request.user
        my_tweet = TweetModel() # 글쓰기 모델 가져오기
        my_tweet.author = user # 모델에 사용자 저장
        my_tweet.content = request.POST.get('my-content', '') # 모델에 글 저장
        my_tweet.save()
        return redirect('/tweet')

 

Ddatabase / tweet

 


 

게시글 읽기/삭제

 

게시글 읽어오기

 

tweet/views.py:

def tweet(request):
    if request.method == 'GET': # GET 방식으로 요청
        user = request.user.is_authenticated  # 사용자의 로그인 확인
        if user: # 로그인한 사용자라면
            all_tweet = TweetModel.objects.all().order_by('-created_at')
            return render(request, 'tweet/home.html', {'tweet':all_tweet})
        else:
            return redirect('/sign-in')
    elif request.method == 'POST':
        user = request.user
        my_tweet = TweetModel()
        my_tweet.author = user
        my_tweet.content = request.POST.get('my-content', '')
        my_tweet.save()
        return redirect('/tweet')

 

all_tweet = TweetModel.objects.all().order_by('-created_at')

타임라인은 최신 글이 상단에 오기 때문에

최신순을 역순으로 정렬되도록 order_by에 -를 붙여줌

 

return render(request, 'tweet/home.html', {'tweet':all_tweet})

tweet/home.html을 화면에 띄우면서 {'tweet':all_tweet}라는 데이터를 화면에 전달

 

읽어온 게시글을 화면에 노출시키기

 

templates/tweet/home.html: 

<div class="row">
    {% for tw in tweet %}
        <div class="col-md-12 mb-2">
            <div class="card">
                <div class="card-body">
                    <div class="media">
                        <div class="media-body">
                            <h5 class="mt-0">{{ tw.content }}</h5>
                        </div>
                        <div style="text-align: right">
                            <span style="font-size: small">{{ tw.author.username }}-{{ tw.created_at|timesince }} 전</span>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    {% endfor %}
</div>

 

{{ tw.author.username}} : 작성자

{{ tw.content }} : 작성된 내용

{{ tw.created_at|timesince}} : 작성된 시간 (|timesince를 하지 않으면 몇월 몇일 몇시 몇분이라고 나온다)

 

게시글 삭제하기

 

tweet/views.py:

from django.contrib.auth.decorators import login_required

@login_required # 로그인 한 사용자만 접근할 수 있게 해주는 기능
def delete_tweet(request, id):
    my_tweet = TweetModel.objects.get(id=id)
    my_tweet.delete()
    return redirect('/tweet')

 

tweet/urls.py:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.home, name='home'), # 127.0.0.1:8000 과 views.py 폴더의 home 함수 연결
    path('tweet/', views.tweet, name='tweet') # 127.0.0.1:8000/tweet 과 views.py 폴더의 tweet 함수 연결
    path('tweet/delete/<int:id>', views.delete_tweet, name='delete-tweet'),
]

 

<int:id>의 숫자는 id에 담겨져 delete_tweet에 전달

이 id를 views.py의 delete_tweet(request, id)에서 매개변수로 받아 사용할 수 있는 것

view와 url이 연결되었으므로, 10번 게시물 삭제는 /tweet/delete/10이라 요청하면 된다

 

templates/tweet/home.html: 

{% if tw.author == user %} # 게시글의 author(글쓴이)와 지금 로그인한 사용자가 같으면
    <div style="text-align: right">
        <a href="/tweet/delete/{{ tw.id }}">
            <span class="badge rounded-pill bg-danger">삭제</span>
        </a>
    </div>
{% endif %}
<div style="text-align: right">
    <a href="#">
        <span class="badge rounded-pill bg-success">보기</span>
    </a>
</div>

 


 

  • @login_required : 로그인 하지 않으면 접근이 불가능하게 만드는 기능
  • user = request.user.is_authenticated : 로그인의 여부만 검증해 주는 기능

 

  • Ctrl + Shift + n : 크롬 시크릿 모드 (로그인 로그아웃 테스트하기 좋음)

 

  • Shift + \ : |