Django 3

·2022년 9월 23일
0

TIL

목록 보기
14/46

장고 연습

1) 파이참 - 장고 파일 생성
2) 재생 버튼 눌러서 장고 서버가 잘 연결되는지 확인

만약 연결된 포트 넘버가 장고에서 이미 사용 중이라는 오류가 난다면, port 8000과 관련된 모든 프로세스를 죽이고 다시 실행시키면 된다

Mac 터미널에서

sudo lsof -t -i tcp:8000 | xargs kill -9" 입력

3) 화면에 글자 띄우기

  • 생성한 패키지에 마우스 올리고 python 파일 생성 [views.py]
from django.http import HttpResponse


def base_response(request):
    return HttpResponse("안녕하세요! 장고의 시작입니다!")
    #HttpResponse() 괄호 안에 있는 내용을 인터넷 창 화면에 보여주는 역할 
  • urls.py 수정
from django.contrib import admin
from django.urls import path
from . import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('test/', views.base_response,name='first_test'),
]

4) 화면에 내가 만든 html 띄우기

  • template 폴더에 html 생성 예) my_test.html
  • views.py에 html 연결
from django.shortcuts import render
#render라는 함수는 template에 있는 html파일을 찾아서 보여준다

def first_view(request):
    return render(request, 'my_test.html')
  • urls.py 변경
from django.contrib import admin
from django.urls import path
from . import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('test/', views.base_response,name='first_test'),
    path('first/', views.first_view,name='first_view'),
]

프로젝트 구조 연습하기

구현하고 싶은 기능
🔰 사용자 관리 (회원가입/로그인/로그아웃)
🔰 글쓰기

1) 앱 생성
user: 사용자 관리 (회원가입/로그인/로그아웃) 담당
tweet: 글 (글쓰기, 삭제, 수정, 댓글) 담당

django-admin startapp user
django-admin startapp tweet

2) 프로젝트 세팅

  • settings.py에 생성한 앱 추가
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'tweet',
    'user',
]

3) 데이터베이스 연결
우측 데이터베이스 클릭 - Data Source from Path 클릭 - 장고가 생성한 db.sqlite3 선택

  • SQLite 클릭 - 연결 테스트 - 확인

4) User Model 만들기

  • user/models.py
#user/models.py
from django.db import models


# Create your models here.
class UserModel(models.Model):
    class Meta:
        db_table = "my_user"

    username = models.CharField(max_length=20, null=False)
    password = models.CharField(max_length=256, null=False)
    bio = models.CharField(max_length=256, default='')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

5) 만든 모델 데이터베이스에 넣기
⭐ 데이터베이스 변경을 알려주는 명령어 makemigrations

python manage.py makemigrations

⭐ 변경된 데이터베이스를 적용시켜주는 migrate

python manage.py migrate

6) Admin 기능

  • 관리자 계정 생성
python manage.py createsuperuser

관리자 생성 후 로그인
관리자 홈페이지에서 회원 아이디 삭제 가능

  • 모델 등록
    user/admin.py
from django.contrib import admin
from .models import UserModel

# Register your models here.
admin.site.register(UserModel) # 이 코드가 나의 UserModel을 Admin에 추가 해 줍니다
  • admin 페이지로 가서 새로고침 하면 UserModel 등록되었는지 확인

위에까지는 user 앱에서 작업한 것 !
아래부터는 tweet 앱 작업

7) tweet 모델 만들기

  • tweet/models.py
# tweet/models.py
from django.db import models
from user.models import UserModel


# Create your models here.
class TweetModel(models.Model):
    class Meta:
        db_table = "tweet"

    author = models.ForeignKey(UserModel, on_delete=models.CASCADE)
    content = models.CharField(max_length=256)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

🔰 ForeignKey는 '외부 모델을 가져와서 사용하겠다.' 라는 뜻
author = models.ForeignKey(UserModel, on_delete=models.CASCADE)

author는 새로운 사람이 아니라, 아까 우리가 만들어 주었던 User Model의 사용자가 작성 한 글 이기 때문에 ForeignKey를 사용해서 넣음

  • 데이터베이스에 알려주고 적용하기
python manage.py makemigrations
python manage.py migrate
  • admin에 넣어주기
    tweet/admin.py
from django.contrib import admin
from .models import TweetModel

# Register your models here.
admin.site.register(TweetModel)
  • admin 페이지 새로고침 후 변경 사항 확인

사용자 관리와 로그인 화면 띄우기

8) 템플릿 만들기 (HTML 작성하기)

  • temlpates에 user 디렉토리 생성 후 아래와 같이 구분 후 각 html 작업

9) url - view - template 이어주기

  • url을 연결할 user앱에 urls,py 생성
  • 그다음 mySpartaSns(프로젝트 폴더명, 가장 상위에 있는) urls.py를 아래와 같이 수정
# 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('user.urls'))
user앱의 urls.py에 연결시키는 코드

  • user의 urls.py에 연결할 user앱의 views.py 작성하기
from django.shortcuts import render


# Create your views here.
def sign_up_view(request):
    return render(request, 'user/signup.html')


def sign_in_view(request):
    return render(request, 'user/signin.html')
  • 작성한 views.py를 urls.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'),
]

10) 사용자 관리와 로그인 - 회원가입 기능 만들기

POST: 값을 주거나 수정, 삭제를 요청할 때 사용
GET: 값을 읽어올 때 사용

  • user의 views.py sign_up_view에 POST 추가하기
# user/views.py
def sign_up_view(request):
    if request.method == 'GET': # GET 메서드로 요청이 들어 올 경우
        return render(request, 'user/signup.html')
    elif request.method == 'POST': # POST 메서드로 요청이 들어 올 경우
        
        return ""
  • HTML에서 form 테그 설정
    signup.html의 form태그 의 속성에 method와 action을 추가
<div class="wrap">
    <h2 class="title-center"> 회원가입 </h2>
    <form class="form-area" method="post" action="/sign-up/">
        {% csrf_token %}
        <div class="form-group mt-2 mb-2"> 
  • user의 views.py에서 전송되는 데이터 받아서 저장하기
    html의 input에 입력 했던 친구들은 각각 username, password, password2, bio로 sign_up_view()함수로 들어가게 된다
from django.shortcuts import render, redirect
from .models import UserModel

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:
            new_user = UserModel()
            new_user.username = username
            new_user.password = password
            new_user.bio = bio
            new_user.save()
        return redirect('/sign-in')

redirect 함수를 이용해서, 저장 완료 되었다면 로그인 페이지 인 /sign-in url로 이동시킨다


11) 사용자 관리와 로그인 - 로그인 기능 만들기

  • url, view 세팅
    : user앱의 views.py에 로그인을 처리해 줄 함수를 만들고, url과 연결
    views.py의 sign_ing_view에 POST 추가
# user/views.py
from django.http import HttpResponse

def sign_in_view(request):
		if request.method == 'POST':
        return HttpResponse("로그인 성공!")
    elif request.method == 'GET':
        return render(request, 'user/signin.html')
  • signin.html의 form 태그 속성 넣기
<!-- 윗부분 생략 -->
<div class="wrap">
    <h2 class="title-center"> 로그인</h2>
    <form class="form-area" action="/sign-in/" method="post">
        {% csrf_token %}
        <div class="form-group mt-2 mb-2">
<!-- 아랫 부분 생략 -->
  • user/views.py 추가
# user/views.py
def sign_in_view(request):
    if request.method == 'POST':
        username = request.POST.get('username', None)
	      password = request.POST.get('password', None)

        return HttpResponse("로그인 성공!")
    elif request.method == 'GET':
        return render(request, 'user/signin.html')

🔥 username과 password를 검사하기 위해서는 사용자를 불러와야 한다

  • user앱의 views.py에 있는 sign_in_view 함수를 아래와 같이 추가
# 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 = UserModel.objects.get(username=username)  # 사용자 불러오기
        if me.password == password:  # 저장된 사용자의 패스워드와 입력받은 패스워드 비교
            request.session['user'] = me.username  # 세션에 사용자 이름 저장
            return HttpResponse(me.username)
        else:
            return redirect('/login')
    elif request.method == 'GET':
        return render(request, 'user/signin.html')

회원가입 중복 방지

# user/views.py
from django.shortcuts import render, redirect
from .models import UserModel


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 = UserModel.objects.filter(username=username)
            
            if exist_user:
                return render(request, 'user/signup.html')  # 사용자가 존재하기 때문에 사용자를 저장하지 않고 회원가입 페이지를 다시 띄움
            else:
                new_user = UserModel()
                new_user.username = username
                new_user.password = password
                new_user.bio = bio
                new_user.save()
                return redirect('/sign-in')

12) 장고 사용자 모델 활용하기

from django.db import models
from django.contrib.auth.models import AbstractUser #장고 모델 불러오기


# Create your models here.
class UserModel(AbstractUser):

    class Meta:
        db_table = "my_user" # 여기는 테이블 이름이에요! 꼭 기억 해 주세요!

    bio = models.TextField(max_length=500, blank=True)
    #내가 생성했던 사용자 모델 중 남기고 싶은 부분 

프로젝트 이름인 폴더(가장 상위 개념)의 setting.py 가장 하단에 아래 코드 추가

# mySpartaSns/settings.py
AUTH_USER_MODEL = 'user.UserModel'

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

python manage.py makemigrations 
python manage.py migrate

14) 장고의 사용자 모델 적용 - 회원가입 수정하기

  • user/views.py
# user/views.py
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') # 회원가입이 완료되었으므로 로그인 페이지로 이동

my_user 데이터 테이블을 살펴보면 password 부분은 장고에 의해 자동적으로 암호화 되어 있다

15) 장고의 사용자 모델 적용하기 - 로그인 수정하기

  • user/views.py 수정하기
# user/views.py
from django.contrib import auth # 사용자 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("로그인 성공")
        else:
            return redirect('/sign-in')  # 로그인 실패
    elif request.method == 'GET':
        return render(request, 'user/signin.html')

from django.contrib import auth 를 사용하면 위처럼 비밀번호까지 체크를 해주고, 로그인 기능까지 간단하게 해결이 가능하다

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

  • template에서 아래와 같이 새로운 폴더 생성 및 페이지 작업

  • 페이지 연결하기
    tweet/views.py

# tweet/views.py
from django.shortcuts import render, redirect


# Create your views here.
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

# 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 함수 연결
]

장고 폴더(가장 상위 개념/프로젝트명) urls.py

# 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'))
]

17) 장고 template 수정하기
home.html

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

base.html

  {% if not user.is_authenticated %}
        <ul class="navbar-nav mr-auto">
            <li class="nav-item active">
                <a class="nav-link" href="/sign-in"> Sign In <span class="sr-only"></span></a>
            </li>
            <li class="nav-item active">
                <a class="nav-link" href="/sign-up"> Sign Up <span class="sr-only"></span></a>
            </li>
        </ul>
    {% else %}
        {{ user.username }} 님 반갑습니다!
    {% endif %}

18) 로그인 필요 기능과 로그아웃 만들기
로그인과 관련된 대표적인 기능

  • 로그인한 사람만 페이지에 접근 가능하게 만들기
  • 로그인한 사람은 사용 안 해도 되는 페이지

📒 로그인한 사람만 페이지에 접근 가능하게 만들기
tweet앱의 views.py를 열어 주시고, 아래의 코드처럼 tweet 함수에 로그인 한 사용자를 판단하는 기능을 추가

# tweet/views.py
from django.shortcuts import render, redirect

def tweet(request):
    if request.method == 'GET':  # 요청하는 방식이 GET 방식인지 확인하기
        user = request.user.is_authenticated  # 사용자가 로그인이 되어 있는지 확인하기
        if user:  # 로그인 한 사용자라면
            return render(request, 'tweet/home.html')
        else:  # 로그인이 되어 있지 않다면 
            return redirect('/sign-in')

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

# user/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')
    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

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':
        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("/")

view 작업 후 url 연결

# user/urls.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')
]

html의 로그아웃 부분을 추가해 주기 위해서 templates 폴더의 base.html 수정

<form class="form-inline my-2 my-lg-0">
    {% if not user.is_authenticated %}
        <ul class="navbar-nav mr-auto">
            <li class="nav-item active">
                <a class="nav-link" href="/sign-in"> Sign In <span class="sr-only"></span></a>
            </li>
            <li class="nav-item active">
                <a class="nav-link" href="/sign-up"> Sign Up <span class="sr-only"></span></a>
            </li>
        </ul>
    {% else %}
        <ul class="navbar-nav mr-auto">
            <li class="nav-item" disabled>
                <span class="nav-link">
                    {{ user.username }} 님 반갑습니다!
                </span>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="/logout"> 로그아웃 </a>
            </li>
        </ul>
    {% endif %}

19) 게시글 쓰기

  • 글 작성할 html 만들기
  • 글 작성할 view 만들기
# tweet/views.py
from .models import TweetModel # 글쓰기 모델 -> 가장 윗부분에 적어주세요!

def tweet(request):
    if request.method == 'GET':  # 요청하는 방식이 GET 방식인지 확인하기
        user = request.user.is_authenticated  # 사용자가 로그인이 되어 있는지 확인하기
        if user:  # 로그인 한 사용자라면
            return render(request, 'tweet/home.html')
        else:  # 로그인이 되어 있지 않다면
            return redirect('/sign-in')
    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')          

20) 게시글 삭제

  • tweet/views.py
# 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':  # 요청 방식이 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')
    TweetModel을 created_at의 역순으로 불러오는 코드. 타임라인은 최신 글이 가장 상단에 있기 때문에 생성된 시간의 역순으로 불러옴

  • return render(request, 'tweet/home.html', {'tweet': all_tweet})
    tweet/home.html을 화면에 띄우면서 {'tweet':all_tweet} 라는 데이터를 화면에 전달

  • tweet/home.html 수정

<!-- templates/tweet/home.html -->
<hr>
<!-- 작성 된 글이 나오는 곳 -->
<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>
  • 글 삭제하기
# 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')

url 연결하기

# tweet/urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('', views.home, name='home'),
    path('tweet/', views.tweet, name='tweet'),
    **path('tweet/delete/<int:id>', views.delete_tweet, name='delete-tweet'),** 추가
]

templates/tweet/home.html 수정하기 <- 삭제, 보기 버튼 나오도록

0개의 댓글