[Django] 개발일지 3

손성수·2023년 4월 4일
0

Django

목록 보기
3/17

Django의 기본 제공 기능

2주차때 createsuperuser라는 명령어로 관리자를 만들고,
관리자 아이디와 패스워드를 이용해 admin에 로그인 했다.
이때 OMR모델을 만들지도 않았는데 로그인 기능을 사용 할 수 있었던 이유는
장고에서 기본으로 제공하는 User(사용자)모델 과 로그인/로그아웃 기능 덕분이다.

데이터베이스 테이블 확인하기

  • auth_user
    장고에서 기본적으로 제겅하는 데이터베이스

  • my_user
    내가 만든 데이터베이스





    우리가 만든 user모델 업그레이드 하기

  1. class의 상속을 이용한다.
  • user앱의, models파일 수정
#user/models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
# AbstractUser Django가 제공하는 기본적인 auth_user테이블과 연동

class UserModel(AbstractUser):
    #장고의 기본 모델을 상속받는다.
    class Meta:
        db_table = "my_user"
    bio = models.CharField(max_length=256, default='')
  • AbstractUser
    • Django가 제공하는 기본적인 auth_user테이블과 연동
  • class로 상속받아 my_user 테이블에는
    • 기존의 name,password,time등의 필드를 작성할 필요가 없어졌다.
  • 장고의 기본모델을 사용하고, bio라는 필드를 추가해줬다는것을 Django에 알릴 필요가 있다.

2. 변경 내용을 장고에게 알리기 * 프로젝트 폴더의 settings.py 이동
 # mySpartaSns/settings.py
AUTH_USER_MODEL = 'user.UserModel'

장고의 사용자 모델을 수정하겠다.
user앱 안에 있는 UserModel 클래스에 적용

user앱에서 작성한 UserModel과 Django기본 auth_user를 결합.





User모델을 데이터베이스에 적용시키기

  • 장고에게 수정한것을 알리고, 적용시키기

    python manage.py makemigrations
    python manage.py migrate

    터미널 명령어, 수정한것을 알리고, 적용시킨다.





Django의 사용자 모델을 적용하기 - 회원가입 수정

user app의 view.py의 sign_up_view 함수를 수정한다.

  • 헤더파일추가
from django.contrib.auth import get_user_model

사용자가 데이터베이스 안에 있는지 검사하는 함수 제공

exist_user = get_user_model().objects.filter(username=username)

데이터베이스에 username을 가진 사용자가 있는지확인

UserModel.objects.create_user(username=username,password=password,bio=bio)

입력받은 데이터베이스 저장





Django의 사용자 모델을 적용하기 - 로그인 수정

데이터베이스를 더블클릭하면, 저장된 데이터를 확인할 수 있다.
password필드에, 기존에 저장한 데이터는 1234지만,
이번에 새로 저장한 데이터는 Django의 암호화 기능이 추가되어 있다.
따라서 로그인시 암호화된 password와 비교하여 로그인을 할 수 있는 기능이 필요하다.

필요한 헤더파일

from django.contrib import auth
me = auth.authenticate(request,username = username,password=password)
  • 암호화된 비밀번호가 현재 비밀번호와 맞는지 확인
  • 또, 그것이 사용자와 맞는지 확인
if me is not None:
	me.login(request,me)
	return HttpResponse(me.username)

if문을 통해 me에 해당하는 정보가 비어있지 않다면, 로그인 성공
me.login(request,me)
Django의 로그인 기능을 이용하여, 사용자를 정보를 반환





로그인 이후 기능 다듬기 - 로그인 후 페이지 이동

  • 템플릿에, tweet 파일 추가
  • tweet파일에 home.html파일 생성
  • 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):
    # 탬플릿의 tweet html파일을 보여주는 함수
    if request.method =='GET':
        return render(request,'tweet/home.html')
    #render : html을 보여주는 함수
  • 매개변수.user.is_authenticated
    • 사용자가 로그인 했는지, 검사해주는 Django내장 기능
  • render
    • html을 보여주는 함수
  • tweet앱 안에 urls.py 생성
# 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('', views.home, name='home'),
    • path가 없을때,127.0.0.1:8000일 때에는 views.py의 home 함수 연결
  • path('tweet/', views.tweet, name='tweet')
    • tweet/ url로 접근시, views.py의 tweet 함수 연결
  • 동작 순서
  1. tweet앱의, views.py
def home(request):
  user = request.user.is_authenticated
      if user:
          return redirect('/tweet')
  • home 함수는, 사용자가 있다면, /tweet url로 보낸다.
  1. tweet앱의 urls.py
path('tweet/', views.tweet, name='tweet')
  • tweet url로 접근시, views.py의 twwet 함수를 호출한다.
  1. tweet앱의 views.py
def tweet(request):
    if request.method =='GET':
        return render(request,'tweet/home.html')
  • render 메소드는 html을 보여주는 함수
  • tweet함수는, 템플릿의 home.html 파일을 보여주는 기능을 한다.

  • 프로젝트 파일의 urls.py에 tweet url 등록하기
    프로젝트 파일의 settings.py - 프로젝트의 모든 환경 설정
    프로젝트 파일의 urls.py - 프로젝트의 모든 url 접속 경로
from django.urls import path,include
from . import views

urlpatterns = [
		.. 기본 기능들 ..
    path('',include('user.urls')),
    path('',include('tweet.urls')),
]

include메소드를 이용해, user,tweet앱의 url을
urlpatterns 리스트에 포함시킨다.
동작순서
1. 사용자로부터 url 요청을 받으면, 프로젝트의 urls.py 접속한다.
2. urlpattens리스트에 path에 해당하는 url이 있는지 검사한다.
3. 해당하는 urldl tweet앱의 url이라면, tweet앱의 urls.py로 이동한다.
4. tweet앱의 urlspattens리스트는, 조건에 맞춰 views.py의 함수를 호출한다.
5. views.py는 조건에 맞춰 사용자가 있는지 확인하고, html을 보여줄지 , redirect메소드를 사용할지 결정한다.

  • user앱의 로그인 기능 다듬기
if me is not None:
    auth.login(request,me)
    return redirect('/')

로그인 성공시, 페이지를 새로고침한다.





로그인 이후 기능 다듬기

  • 로그인 이후 화면

문제점
1. 로그인을 했는데도 회원가입,로그인 박스가 나타난다.
2. 로그인을 한 유저의 정보가 출력되는 것이 없다.

  • 탬플릿의 tweet폴더의 home.html파일 이동
<h5 class="card-title">{{ user.username }}</h5>
<p class="card-text">{{ user.bio }}</p>

탬플릿 문법 {{ }}
Django의 템플릿 문법을 사용해 card-title에 유저의 정보를 출력한다.

  • 템플릿의 user폴더의 base.html 파일이동
<form class="form-inline my-2 my-lg-0">
            {% if not user.is_authenticated %}
            --  기본적으로 보여줄 네비게이션 코드 --
            {% else %}
                {{ user.username }} 님 반갑습니다!
            {% endif %}
        </form>

템플릿 문법 {% %}

{% if not user.is_authenticated %}
만약, 사용자가 로그인 한 상태가 아니라면 참이된다.
{% else %}
로그인 한 상황이 아니라면 출력할 코드 작성
{% endif %}
조건 분기문을 종료하겠다.





로그인 필요 기능과, 로그아웃 기능 만들기

문제점
1. tweet/ url로 접속시, 로그인 해야만 접속할 수 있는
로그인을 하지 않아도 페이지에 접속할 수 있다.
2. 로그인,로그아웃 기능이 없다

  • tweet 접속시, 로그인을 하지 않았으면 로그인 페이지로 이동하는 기능 만들기.
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')

user = request.user.is_authenticated
장고의 내장 기능 user.is_authenticated를 이용하여, 로그인한 상태인지 확인한다.
if문을 통해 로그인을 했으면 render메소드, html을 보여주는 메소드를 통해
home.html을 보여준다
else문을 통해 , 로그인을 하지 않았다면, redirect메소드를 이용해 로그인 페이지로 이동한다.

추가 문제점 발견
1. 로그인한 상황에서 sign-in,sign-up 페이지로 이동시
로그인한 상황임에도 불구하고, 로그인 페이지,회원가입 페이지로 이동할 수 있다.

  • user app의 views.py 이동
def sign_up_view(request):
    if request.method == 'GET':
        user = request.user.is_authenticated
        if user:
            return redirect('/')
        else :
            return render(request,'user/signup.html')

똑같이 Django 내장기능 request.user.is_authenticated
를 통해 로그인 한 상태인지 확인하여
로그인한 상황이라면, 회원가입 페이지에 접속할 수 없게끔 제한한다.

  • return redirect('/')
    • '/'함수는 사용자가 요청했던 원래의 위치로 이동한다.
    • 우리의 코드의 경우 tweet의 views.py의 home 함수를 확인해야한다.
  • tweet app의, views.py
def home(request):
    user = request.user.is_authenticated
    if user:
        return redirect('/tweet')
    else:
        return redirect('/sign-in')

home함수는 사용자가 있다면 tweet페이지로 이동
없다면 sign-in 페이지로 이동하는 기능을 하고 있다.

  • 로그인 페이지도, 로그인한 상태라면, 접근할수 없게 제한하기

  • user app의 views.py이동

def sign_in_view(request):
	if *--(POST방식)--*:
    	*--로그인 할 수 있는지, 없는지 작동하는 기능--*
    
    #GET 방식
	elif request.method == 'GET':
	user = request.user.is_authenticated
		if user:
			return redirect('/')
		else :
			return render(request, 'user/signin.html')

마찬가지로 장고의 내장 기능 매개변수.user.is_authenticated 를 이용하여
인증을 받은 상황이라면, redirect한다.



  • 로그아웃 기능 만들기

  • user app의 views.py이동

def logout(request):
    auth.logout(request)
    return redirect('/')

auth.logout(매개변수)
Django의 내장기능, 로그아웃 기능을 작동하고
redirect를 이용해, 이전 요청으로 돌아간다.

  1. 문제 로그 아웃 기능은, 로그인한 유저만 볼 수 있어야하는 기능이다.
from django.contrib.auth.decorators import login_required
@login_required
def logout(request):
    auth.logout(request)
    return redirect('/')

Django의 내장기능을 사용하여, 로그인이 되어있어야만 사용할 수 있는 함수임을 알린다.


  • user app의 urls.py 이동
urlpatterns = [
	# -- 로그인, 회원가입 url 생략  --#
    path('logout/',views.logout,name='logout'),
]

urlpatterns에 logout url 추가

  • logout에 접속할 수 있는 버튼 만들기

  • 템플릿의 base.html이동

 <form class="form-inline my-2 my-lg-0">
            {% if not user.is_authenticated %}
				사용자가 로그인 하지 않은 상황일때 동작할 구간
   
            {% 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"> 로그아웃 </a>
                    </li>
                </ul>
            {% endif %}
        </form>
  • disabled 클릭하지 못하게 설정, {username}
  • href="/logout" 로그아웃을 클릭하면, 로그아웃 접속




게시글 쓰기

  • 같은 url이라도 접근하는 방식에 따라서 기능이 달라질 수 있다.

  • 템플릿의 home.html 이동

<form action = '/tweet/' method = 'post'>
 {% csrf_token %}
    <div>
        <textarea name='my-content'</textarea>
      # 사용자가 글을 작성하는 영역  - my-content
    </div>
    <button type="submit">작성하기</button>
 </form>

form 태그 안, submit으로 form태그를 작동,
tweet앱의 views로 이동하고 데이터는 post형태로 보낸다.
이때 csrf_token은 보안 Django의 보안 기능이 내포되어 있다.

  • 동작순서
    html submit으로 form태그로 tweet앱 동작
    tweet앱의 urls.py에서 urlpatterns 리스트의 views.tweet 동작
    views.py 실행
from .models import TweetModel
# TweetModel 가져오기

TweetModel import

def tweet(request):
    # 탬플릿의 tweet html파일을 보여주는 함수
    if request.method =='GET':
        //로그인 했을때 , 안했을때의 동작 생략
        
    elif request.method == 'POST':  # 요청 방식이 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')




게시글 읽기 삭제

def tweet(request):
    # 탬플릿의 tweet html파일을 보여주는 함수
    if request.method =='GET':
        user = request.user.is_authenticated
        if user:
            all_tweet = TweetModel.objects.all().order_by('-created_at')
            render(request,'tweet/home.html',{'tweet':all_tweet})
        else:
            return redirect('/sign-in')
  • user = request.user.is_authenticated
    인증된 사용자인지(로그인한 사용자) 판단
  • all_tweet = TweetModel.objects.all().order_by('-created_at')
    TweetModel.objects.all()
    트윗모델에 저장한 모든 데이터를 불러온다.
    .order_by('-created_at')
    트윗이 생성된 역순으로 정렬한다.
  • return render(request,{'tweet/home.html':all_tweet})
    home.html에 딕셔너리 형태로 데이터를 넘긴다.
    key - tweet
    value - all_twet

정렬 단축기 ctrl + alt + l

html 작성 요약,( 필요한 기능만 )

{% for tw in tweet %}
{{ tw.content }}
{{ tw.author.username }}-{{ tw.created_at|timesince }} 
{% endfor %}
  • {% for tw in tweet %}
    • tweet을 key값으로 for 반복문을 돈다.
  • {{ tw.content }}
    • 데이터베이스의 content를 불러온다.
  • tweet app의 models.py
author = models.ForeignKey(UserModel, on_delete=models.CASCADE)

author는 UserModel을 담고 있다.

  • {{ tw.author.username }}-{{ tw.created_at|timesince }}
    • tw.author는 UserModel이 갖고있는 모든 데이터를 가져온다.
    • 그중 username을 호출하여 가져온 코드
  • tw.created_at
    • 작성한 날 , 몇월 몇시 몇분이 출력
    • timesince를 출력하여, 작성시간 - 현재시간의 차이값을 출력한다.
  • {% endfor %}
    • 반복문 종료

  • 삭제 기능 만들기

삭제 할 기능을 추가 할 url은 http://127.0.0.1:8000/tweet/delete/게시글의id 입니다.
만약, 2번 게시글을 삭제하고 싶다면 tweet/delete/게시글id/2

  • tweet app의 views.py 이동
from django.contrib.auth.decorators import login_required
#어떤 함수가 동작할때 로그인 되어 있어야만 동작할 수 있는 데코레이터 import

@login_required()
def delete_view(request,id):
    my_tweet = TweetModel.objects.get(id=id)
    my_tweet.delete()
    return redirect('/tweet')

삭제 기능함수
데코레이터 함수로, 로그인이 되어 있어야만 동작할 수 있는 기능이 포함되어 있다.

  • tweet app의 urls.py이동
urlpatterns = [
    path('tweet/delete/<int:id>', views.delete_tweet, name='delete-tweet'),
]

urlpatterns 리스트의 url 생성
<int:id> : 삭제할 tweet의 id를 반환
views.delete_tweet : views.py의 delete_tweet 함수 호출

  • 템플릿의 home.html 에 게시글 삭제 기능 구현
{% if tw.author == user %}
#현재 로그인한 사용자가, 글을 작성한 유저라면
<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>

{% if tw.author == user %} : 이게시글의 작성자가, 현재 로그인한 작성자인지 확인





이번 강의 내용

  1. 나만의 장고 사용자를 모델을 만들었다.
    기존의 데이터베이스를 확장하여 장고 데이터베이스 확장하여 연결(클래스 상속)

  2. 회원가입,로그인,로그아웃 기능을 만들었다.

  3. 게시글 작성, 삭제,읽어오는 기능을 만들었다.





숙제

tweet의 게시글에 댓글 작성,불러오기,삭제 기능 만들기

  1. model 추가하기
    class TweetComment(models.Model):
       class Meta:
           db_table = "comment"
       tweet = models.ForeignKey(TweetModel, on_delete=models.CASCADE)
       author = models.ForeignKey(UserModel, on_delete=models.CASCADE)
       comment = models.CharField(max_length=256)
       created_at = models.DateTimeField(auto_now_add=True)
       updated_at = models.DateTimeField(auto_now=True)
    • TweetComment 클래스 추가
      • 장고의 model을 상속받았다.
      • tweet : TweetModel의 모든 데이터를 저장하는 변수
      • author : UserModel의 모든 데이터를 저장하는 변수
      • comment : 데이터의 필드
  2. 모델의 추가한점을 Django에게 알리고, 적용하기
    실행중이라면 정지를 누르자.
    터미널 입력
python manage.py makemigrations
python manage.py migrate


  1. tweet.views 수정
    tweet.models.py에 작성한 class import하기
from .models import TweetComment


소스코드 작성

@login_required
def detail_tweet(request, id):
    my_tweet = TweetModel.objects.get(id=id)
    tweet_comment = TweetComment.objects.filter(tweet_id=id).order_by('-created_at')
    return render(request,'tweet/tweet_detail.html',{'tweet':my_tweet,'comment':tweet_comment})
  • @login_required
    • 로그인을 했을때만, 함수가 실행될 수 있도록 제한하는 데코레이터
  • def detail_tweet(request, id):
    • 불러오기 함수, 인자값으로 id를 받는다.
  • my_tweet = TweetModel.objects.get(id=id)
    • id에 해당하는 필드의 데이터를 저장한다.
  • tweet_comment = TweetComment.objects.filter(tweet_id=id).order_by('-created_at')
    • TweetComment클래스에 저장된 데이터를 id값을 조회하여 해당하는 데이터만을 저장하는데, 최신순으로 내림차순하여 정렬한다.
  • return render(request,'tweet/tweet_detail.html',{'tweet':my_tweet,'comment':tweet_comment})
    • render메소드는, html을 사용자에게 보여주는 기능을 한다.
  • tweet':my_tweet,'comment':tweet_comment}
    • 데이터를 딕셔너리 형태로 보낸다.
@login_required
def write_comment(request, id):
    # 댓글 작성 함수, 데코레이터로 로그인한 사용자만 인증받아 작성할 수 있는 내장 기능이 첨가되어 있다.
    if request.method == 'POST':
        #POST방식일때 동작
        comment = request.POST.get("comment","")
        # 전달받은 데이터를 comment 변수에 저장
        current_tweet = TweetModel.objects.get(id=id)
        # TweetModel의 데이터베이스 필드중 id값과 일치하는 모든 데이터를 변수에 저장한다.

        TC = TweetComment()
        #TweetComment클래스의 객채 생성
        TC.comment = comment
        TC.author = request.user
        TC.tweet = current_tweet
        # POST방식으로 전달된 데이터를 객체에 저장하고

        TC.save()
        #데이터를 저장한다.

        return redirect('/tweet/'+str(id))
        # id순서에 맞는 페이지를 반환한다.
@login_required
def delete_comment(request, id):
    #댓글 삭제기능, 데코레이터로 로그인한 사용자만 접근할 수 있다.
    comment = TweetComment.objects.get(id=id)
    #TweetComment클래스의 id필드에, 매개변수 id에 해당하는 댓글 데이터를 불러온다.
    current_tweet = comment.tweet.id
    #tweet id, 현재 게시글의 위치값을 반환한다.
    comment.delete()
    # 해당하는 댓글 데이터 삭제
    return redirect('/tweet/'+str(current_tweet))
    #게시글에 해당하는 페이지를 반환한다.
profile
더 노력하겠습니다

0개의 댓글

관련 채용 정보