파일 불러오기
from django.http import HttpResponse : 장고의 http에서 HttpResponse를 사용하겠다는 뜻.
path('', views.home) : 경로를 정해주는 코드. 전부 괄호에 넣어야 한다.
from django.shortcuts import render : 장고의 숏컷에서 랜더를 사용하겠다는 뜻.
return render(request, 'test.html') : 전해줄 html을 적는 코드. request를 빼먹지 말자.
 
모델 만들기
models.Model을 상속으로 주는 이유는 여러가지 필드라거나, ORM만들어주는 속성들이 있다.
 
관리자 만들기
from .models import UserModel : 모델을 사용하겠다는 뜻.
admin.site.register(UserModel) : 관리자 페이지에 등록하겠다는 뜻.
 
회원가입 기능 만들기
action의 url은 urls에서 정한 값이다.
html수정하고 views에서 데이터 받아온거 저장하면 됌.
 
로그인 기능 만들기
request.session 은 각 키마다 값을 가지고 있는 dictionary 와 비슷한 형태
request.session['user'] = me.username
user라는 키에 username이라는 값을 저장한다.
 
장고 유저모델 사용하기
from django.contrib.auth.models import AbstractUser
contrib은 장고의 패키지다.
장고의 contrib패키지에서 인증 모델 중에 AbstractUser를 사용하겠다는 뜻.
상속을 시켜주면 된다.
프로젝트에 알려줘야한다.
AUTH_USER_MODEL = 'user.UserModel'
이 뜻은 user앱에서 작성한 UserModel을 사용한다는 뜻이다.
 
장고 모델로 수정하기
get_user_model : 사용 할 수 있는 계정인지 판단하는 기능 불리안.
 
tweet 연결하기
request.user.is_authenticated : 유저가 인증을 받았는지.
 
url 정리하기.
로그인을 했다.
= 메인페이지 보여야함.
로그인 안했다.
= 회원가입, 로그인이 보여야함.
 
데이터 전송하기
all_tweet = ......
retrun.... {'tweet':all_tweet}
 
코멘트 작성하기.
관례에 따라, Django는 외래 키 필드명에 "_id" 이름을 자동으로 추가합니다.
즉 외래 키의 아이디를 지칭 하는 말이 라는 것. tweet_id
 
토핑 참조 확인하기
_set
"Answer" → 대문자를 소문자로 변경 + "_set" 을 붙인다가 규칙
QuerySet은 모델의 객체인데 이 set이 _set인 듯 하다.
 
exclude: 들어오지 못하게 하다.
 
역참조. 팔로우 하기, 취소하기.
상대를 팔로우 하는 모든 사람들 중에
내가 없다면 팔로우.
있다면 팔로우 취소.
 
 
 
 
 
 

'Django' 카테고리의 다른 글

장고 정리: 5주  (0) 2023.04.12
무신사 ERD  (0) 2023.04.09
파이썬 장고 실무 기초: 4  (0) 2023.04.05
파이썬 장고 실무 기초: 3  (0) 2023.04.05
파이썬 장고 실무 기초: 2  (0) 2023.04.04
회원가입, 로그인 시 에러 메세지 띄워주기
에러가 날 상황을 if문으로 정의를 해주고
error라는 이름으로 데이터를 보내주고
html에서 데이터를 받도록 수정한다.
 
글 작성 시 공백이면 에러 띄우기
post에서 실패 후 다시 render가 된다면 post요청이 되었던 것이기 때문에
get에서 띄워줬던 all_tweet은 긁어오지 못하게 된다.
post에 또 한번 적어주자.
content가 공백이라면 에러 띄워주고, 데이터도 띄워준다.
아니라면 데이터 저장~
html에서 에러를 띄워주도록 수정한다.
 
로그인이 된 상태에서만 친구 버튼 보이기!
유저가 로그인 이라면~ 을 html에 추가해주면 된다.
 
태그를 붙여보자!(적용)
태그 모듈 다운로드
pip install django-taggit
pip install django-taggit-templatetags2
장고에게 알려주기.
'taggit_templatetags2',
'taggit.apps.TaggitAppConfig',
태그 모듈에 필요한 정보라 추가.
TAGGIT_CASE_INSENSITIVE =True
TAGGIT_LIMIT = 50
게시글에 태그를 달 것이기 때문에 트위트 모델에 입력한다.
from taggit.managers import TaggableManager
tags = TaggableManager(blank=True)
db에 알려주기
python manage.py makemigrations
python manage.py migrate
 
이제 진짜로 태그를 사용해보자.
이것은.. 만든 것을 잘 복붙해서 사용을 하자.

'Django' 카테고리의 다른 글

스파르타 장고. 잘 못하는 것들.  (0) 2023.04.13
무신사 ERD  (0) 2023.04.09
파이썬 장고 실무 기초: 4  (0) 2023.04.05
파이썬 장고 실무 기초: 3  (0) 2023.04.05
파이썬 장고 실무 기초: 2  (0) 2023.04.04

https://www.erdcloud.com/d/Nc5NE8DrLKLdCvQe4

'Django' 카테고리의 다른 글

스파르타 장고. 잘 못하는 것들.  (0) 2023.04.13
장고 정리: 5주  (0) 2023.04.12
파이썬 장고 실무 기초: 4  (0) 2023.04.05
파이썬 장고 실무 기초: 3  (0) 2023.04.05
파이썬 장고 실무 기초: 2  (0) 2023.04.04

데이터 베이스 관계

one-to-many - 작성자 > 글들
one-to-one - 유저 > 프로필
many-to-many 피자 > 토핑
 

Many-To-Many 연습을 위한 앱 생성

앱생성
django-admin startapp restaurant
앱 연결
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'tweet',
    'user',
    'restaurant', #요기

Many-To-Many 모델 등록하기 (연습 - 피자/토핑)

모델 만들기
# restaurant/models.py
from django.db import models


# Create your models here.

class MyTopping(models.Model):
    class Meta:
        db_table = "my_topping"

    def __str__(self):
        return self.topping_name

    topping_name = models.CharField(max_length=100)


class MyPizza(models.Model):
    class Meta:
        db_table = "my_pizza"

    def __str__(self):
        return self.pizza_name

    pizza_name = models.CharField(max_length=100)
    pizza_topping = models.ManyToManyField(MyTopping)
터미널에 입력
python manage.py makemigrations
python manage.py migrate
어드민 페이지에 데이터베이스 모델 추가하기.
restaurant의 admin.py에 추가하기
from django.contrib import admin
from .models import MyTopping, MyPizza

# Register your models here.

admin.site.register(MyPizza)
admin.site.register(MyTopping)
user모델을 수정했기 때문에 접근 가능한 admin 계정이 없다.
계정 재생성.
python manage.py createsuperuser
 
관리자 페이지 가서 토핑 저장보면 에러가 난다!
장고가 createsuperuser를 잘 인식 못해서 그렇다고 한다.
db,migrations의 __init__.py 빼고 삭제!
다시 장고한테 알려주고 db에 반영하기.
python manage.py makemigrations
python manage.py migrate
db도 다시 연결해주고, 관리자도 재생성하면 에러 해결!

Django Shell로 Many-To-Many 모델 확인 해 보기

Django Shell : Django를 실행하지 않고도 기능들을 사용 할 수 있도록 도와주는 도구
터미널에 입력해서 실행!
python manage.py shell
피자에 있는 토핑 확인하기
>>> from restaurant.models import MyTopping, MyPizza

#전체 피자
>>> MyPizza.objects.all()
<QuerySet [<MyPizza: 도미노>, <MyPizza: 피자헛>, <MyPizza: 파파존스>]>

# 피자를 하나씩 불러볼게요
>>> MyPizza.objects.get(pizza_name='도미노')
<MyPizza: 도미노>
>>> MyPizza.objects.get(pizza_name='피자헛')
<MyPizza: 피자헛>
>>> MyPizza.objects.get(pizza_name='파파존스')
<MyPizza: 파파존스>

# 각 피자의 토핑들을 불러볼게요
>>> MyPizza.objects.get(pizza_name='도미노').pizza_topping.all()
<QuerySet [<MyTopping: 치즈>, <MyTopping: 치킨>]>
>>> MyPizza.objects.get(pizza_name='피자헛').pizza_topping.all()
<QuerySet [<MyTopping: 치즈>, <MyTopping: 페퍼로니>, <MyTopping: 올리브>]>
>>> MyPizza.objects.get(pizza_name='파파존스').pizza_topping.all()
<QuerySet [<MyTopping: 치즈>, <MyTopping: 페퍼로니>, <MyTopping: 피망>]>
토핑이 있는 피자 가져오기
>>> from restaurant.models import MyTopping, MyPizza

#전체 토핑
>>> MyTopping.objects.all()
<QuerySet [<MyTopping: 치즈>, <MyTopping: 페퍼로니>, <MyTopping: 올리브>, <MyTopping: 치킨>, <MyTopping: 피망>]>

#각 토핑별로 출력
>>> MyTopping.objects.get(topping_name='치즈')
<MyTopping: 치즈>
>>> MyTopping.objects.get(topping_name='페퍼로니')
<MyTopping: 페퍼로니>
>>> MyTopping.objects.get(topping_name='올리브')
<MyTopping: 올리브>
>>> MyTopping.objects.get(topping_name='치킨')
<MyTopping: 치킨>
>>> MyTopping.objects.get(topping_name='피망')
<MyTopping: 피망>

# 각 토핑이 들어있는 피자를 불러오기
>>> MyTopping.objects.get(topping_name='치즈').mypizza_set.all()
<QuerySet [<MyPizza: 도미노>, <MyPizza: 피자헛>, <MyPizza: 파파존스>]>
>>> MyTopping.objects.get(topping_name='페퍼로니').mypizza_set.all()
<QuerySet [<MyPizza: 피자헛>, <MyPizza: 파파존스>]>
>>> MyTopping.objects.get(topping_name='올리브').mypizza_set.all()
<QuerySet [<MyPizza: 피자헛>]>
>>> MyTopping.objects.get(topping_name='치킨').mypizza_set.all()
<QuerySet [<MyPizza: 도미노>]>
>>> MyTopping.objects.get(topping_name='피망').mypizza_set.all()
<QuerySet [<MyPizza: 파파존스>]>
Mnay-To-Many 모델은 '서로의 테이블에서' 서로의 데이터를 불러 올 수 있는 것이 특징
 

many-to-many 모델 만들어보기

사람 간의 모델이기 때문에 many-to-many 모델을 user 모델을 추가할 거다.
# user/models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.conf import settings

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

    class Meta:
        db_table = "my_user"

    bio = models.TextField(max_length=500, blank=True)
    follow = models.ManyToManyField(settings.AUTH_USER_MODEL,related_name='followee')
세팅 파일을 그대로 가져오는게 아니라 장고가 관리하는 세팅을 가져오는 이유는 나중에 세팅을 여러 파일로 나누어 적용하게 되는데 알아서 세팅파일을 가져오도록 하는 것.
 
이제 장고에게 또 알려줘야지.
python manage.py makemigrations
python manage.py migrate
그리고 계정을 여러 개 만들고 어드민에서 팔로우를 추가 하여 데이터를 만들어보자.
 

Many-To-Many 모델 사용하기 (실전-친구 리스트/팔로우)

친구 리스트를 보여주는 기능!
팔로우 당할 사람이 click_user다. 이 사람의 팔로워들을 전부 가져와서 내가 없다면 팔로우 버튼이 보이고, 있다면 팔로우 취소 버튼이 보이도록 할거다.
views에 기능을 추가해주고.
# user/views.py 

@login_required
def user_view(request):
    if request.method == 'GET':
        # 사용자를 불러오기, exclude와 request.user.username 를 사용해서 '로그인 한 사용자'를 제외하기
        user_list = UserModel.objects.all().exclude(username=request.user.username)
        return render(request, 'user/user_list.html', {'user_list': user_list})


@login_required
def user_follow(request, id):
    me = request.user
    click_user = UserModel.objects.get(id=id)
    if me in click_user.followee.all():
        click_user.followee.remove(request.user)
    else:
        click_user.followee.add(request.user)
    return redirect('/user')
urls에 url 연결을 해주자.
path('user/', views.user_view, name='user-list'), 
path('user/follow/<int:id>',views.user_follow, name='user-follow')
그리고 user.html을 만들어주자.
  • views.py에서 전달 해 주는 user_list에 담겨있는 사용자를 {% for %} 로 반복해서 출력
  • 로그인 한 사용자는 {{ user }} 으로 출력합니다. 위에서 {{ ul }} 로 출력 해 주는 사용자는, views.py의 user_view함수에서 전달 받은 사용자
  • 아래에 있는 '팔로우' 혹은 '팔로우 취소' 링크는 views.py에서 생성한 user_follow 함수와 이어져 있음.
→ user.follow.all()는 해당 사용자가 팔로우 하는 사람들을 불러옵니다.
→ user.followee.all()는 해당 사용자를 팔로우 하는 사람들을 불러옵니다.
그리고 상단 네비게이션에 친구 버튼에 하이퍼링크를 추가 해주자.

'Django' 카테고리의 다른 글

장고 정리: 5주  (0) 2023.04.12
무신사 ERD  (0) 2023.04.09
파이썬 장고 실무 기초: 3  (0) 2023.04.05
파이썬 장고 실무 기초: 2  (0) 2023.04.04
파이썬 장고 실무 기초: 1  (0) 2023.04.03

장고의 모델 vs 나의 모델

장고에는 담을 수 있는 내용이 많은 테이블을 기본적으로 많이 제공해준다.
나의 모델과 장고의 모델을 합쳐 사용하면 더 좋게 개발 할 수 있다.
 

User모델 업그레이드

장고에서 기본적으로 제공하는 모델을 사용하기 위한 방법.
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) #필요한 테이블만 남기고 나머지는 삭제.
Django는 auth_user를 사용자 관리 테이블로 지정 해 놓았어요. 우리가 만든 모델로 이것을 바꾸려면 Django에게 알려주어야 합니다.
settings.py 맨 밑에 밑에 코드 추가.
AUTH_USER_MODEL = 'user.UserModel'
Django에게 기본 인증과정 (AUTH_USER_MODEL)을 user앱에 작성한 UserModel로 사용하겠다! 라고 알려주는 과정

user모델 적용시키기.

터미널에 입력!
python manage.py makemigrations  
python manage.py migrate

사용자 모델 적용시키기 - 회원가입 수정하기.

맨 위에 밑에 코드 추가하고.
# user/views.py 
from django.contrib.auth import get_user_model #사용자가 있는지 검사하는 함수
유저모델을 사용하도록 수정을해보자.
# user/views.py 
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에 맨 위에 추가.
auth는 authentication( 유저 인증 )
contrib은 contributed ( 기여하다 )
# user/views.py 
from django.contrib import auth # 사용자 auth 기능

 

# 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 HttpResponse("로그인 성공") 
        else: 
            return redirect('/sign-in')  # 로그인 실패 
    elif request.method == 'GET': 
        return render(request, 'user/signin.html')
from django.contrib import auth 를 사용하면 위처럼 비밀번호까지 체크를 해 주고, 로그인 기능까지 간단하게 해결이 가능.
 

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

로그인 후 로그인이 되었다는 글만 띄어주고 있다. 글을 쓸 수 있는 페이지로 이동을 시키자.

html 만들기

tweet이라는 폴더를 templates에 만들고 home.html을 만든다.

home.html 연결하기.

views.
# 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')
user = request.user.is_authenticated → 장고가 제공하는 사용자 모델을 사용 했을 때 쓸 수 있는 함수인데요, '사용자가 로그인 했는지' 검사 해 주는 기능
urls.
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 함수 연결 
]
장고에 알려주기
# 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')) 
]
로그인 시 글 출력을 home.html로 이동 하도록 수정.
#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')
 

로그인 이후 기능 다듬기

로그인 후에 부트스트랩에서 가져온 카드의 내용이 있으니 수정!!
<div class="col-md-3"> 
    <div class="card"> 
        <div class="card-body"> 
            <h5 class="card-title">{{ user.username }}</h5> 
            <p class="card-text"> {{ user.bio }}</p> 
        </div> 
    </div> 
</div>
로그인 후에도 로그인 하기와 회원가입 버튼이 있다. 수정!!
<!-- templates/base.html --> 
		... 생략  
				<li class="nav-item"> 
            <a class="nav-link" href="#"> 친구 <span class="sr-only"></span></a> 
        </li> 
    </ul> 
</div> 
<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 %} #요줄 중요! 
        {{ user.username }} 님 반갑습니다! 
    {% endif %} # 요줄은 if 문이 끝났다는 걸 알려주는 것 같다!
</form> 
... 생략
 

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

로그인과 관련된 기능은 대표적으로 두 가지가 있습니다!
  1. 로그인 한 사람만 페이지에 접근 가능하게 만들기
  2. 로그인 한 사람은 사용 안 해도 되는 페이지
현재 로그인하면 로그인,회원가입 버튼이 보이고 들어 갈 수도 있고, 로그아웃 버튼이 없는 문제가 있다.
로그인 하지 않았는데도 home.html로 이동 할 수 있는 문제도 있다.

로그인 해야 home.html로 갈 수 있도록 해보자.

# 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("/")
@login_requireduser = request.user.is_authenticated 은 모두 로그인 한 사람들만 사용 할 수 있도록 도와주는 기능
 
로그아웃 urls 추가
# 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 --> 
		... 생략  
				<li class="nav-item"> 
            <a class="nav-link" href="#"> 친구 <span class="sr-only"></span></a> 
        </li> 
    </ul> 
</div> 
<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 %} 
</form> 
... 생략
<a class="nav-link" href="/logout"> 로그아웃 </a> 부분이 우리의 로그아웃을 도와주는 부분
 

게시글 데이터베이스에 저장하기.

html에서 post로 데이터 보내기.
... 생략 
<form action="/tweet/" method="post"> 
    {% csrf_token %} 
    <div class="form-group mb-2"> 
        <textarea class="form-control" style="resize: none" name='my-content' id="my-content"></textarea> 
    </div> 
    <button type="submit" class="btn btn-primary" style="float:right;">작성하기</button> 
</form> 
... 생략
tweet으로 보냈으니까 url이 어느 함수로 연결 되어있는지 확인해보자.
from django.urls import path 
from . import views 
urlpatterns = [ 
    path('', views.home, name='home'), 
    path('tweet/', views.tweet, name='tweet') 
]
urls 확인하기. views.tweet이니까 views로 가서 tweet 함수를 찾자.
그리고 post로 데이터가 온 것을 저장하자.
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')
 
 

게시글 데이터 출력 / 삭제

게시글 출력하기.

데이터를 담아서 home.html에 보내준다.
# 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')
이제 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>

글 삭제

삭제 기능을 views에 추가한다.
# 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을 누르면 views에 기능이 실행되도록 추가한다.
# 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'),
]
tweet/delete/<int:id> 는, tweet/delete/123 과 같이 맨 뒷자리에 숫자가 온다는 얘기이고, 이 숫자는 id에 담겨져 delete_tweet에 전달
html에 삭제버튼을 띄워주고 게시글에 id를 대입 해준다.
<!-- 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">
                    {% 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> 
                    <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>

... 생략
  • 이 게시글의 author (글쓴이) 와, 로그인 한 사용자가 같을 때에만 '삭제' 버튼이 나타납니다
  • 삭제 버튼은 /tweet/delete/tw.id 로 연결이 되는데, 이 tw.id는 게시글의 고유 id값입니다!

'Django' 카테고리의 다른 글

장고 정리: 5주  (0) 2023.04.12
무신사 ERD  (0) 2023.04.09
파이썬 장고 실무 기초: 4  (0) 2023.04.05
파이썬 장고 실무 기초: 2  (0) 2023.04.04
파이썬 장고 실무 기초: 1  (0) 2023.04.03

프로젝트 구조 만들기

sns기능을 생각하면
사용자 관리(회원가입/로그인/로그아웃)
글쓰기
친구만들기
로 나누어 볼 수 있다.
크게 사용자와 글쓰기로 나누어 볼 수 있고 관련된 앱을 만든다.
터미널에 입력한다.
django-admin startapp user #사용자 관리 담당할 user
django-admin startapp tweet #글 관리 담당할 tweet
user, tweet이라는 앱이 만들어지면서 폴더와 필요한 파일들이 생성된다.
앱이 만들어졌으니 settings.py에서 앱을 사용할 수 있도록 수정 해줘야 한다.
INSTALLED_APPS = [ 
    'django.contrib.admin', 
    'django.contrib.auth', 
    'django.contrib.contenttypes', 
    'django.contrib.sessions', 
    'django.contrib.messages', 
    'django.contrib.staticfiles', 
    'tweet', #
    'user',  # 두개 추가!
]

데이터베이스와 장고 ORM 알아보기

데이터 베이스 연결

장고가 잘 실행되면 데이터베이스가 자동으로 생긴다.
파이참 우측 상단에 있는 데이터베이스를 클릭해서 경로에서 데이터베이스를 찾고 sqlite로 데이터베이스를 연결하고 드라이버를 설치해주면 연결 할 수 있다.
settings.py  밑쪽을 보면 데이터베이스가 생성되도록 적혀져 있다.

ORM

데이터베이스를 객체로 보고 SQL언어가 아닌 클래스로 쉽게 표현, 사용 할 수 있게 해줌. 클래스로 표현한 형태가 모델이다.

유저모델 만들기

유저 모델에 필요한 요소는 무엇일지 고민을 해야한다.
유저이름, 비밀번호, 바이오, 생성일, 수정일을 받기로 정하였다.
메타는 db에 테이블의 이름을 정하고 저장해준다.
각 필드는 어떤 정보가 들어갈 건지 설정할 수 있다.
#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)

만든 유저모델 관리자 페이지에 넣기

데이터베이스의 변경을 알려줘야한다.

python manage.py makemigrations
변경된 모델의 이름이 출력이 되면 완료.

 

데이터베이스에 변경을 반영해야한다.
python manage.py migrate
관련된 이름이 출력되면 완료.
 

admin 기능 맛보기

/admin 으로 이동하면 관리자 페이지로 갈 수 있다.
관리자로 로그인할 수퍼유저를 만들어야한다.
터미널에 입력!
python manage.py createsuperuser
 
admin에 모델을 불러와서 모델을 만들고 수정 할 수 있도록 할 수 있다.
user의 admin에 추가한다.
from django.contrib import admin
from .models import UserModel



# Register your models here.

admin.site.register(UserModel) # 이 코드가 나의 UserModel을 Admin에 추가 해 줍니다
 

tweet모델 관리자 페이지에 넣기

tweet 모델 먼저 만든다.
# 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)
    #ForeignKey는 '외부 모델을 가져와서 사용하겠다.' 라는 얘기
    content = models.CharField(max_length=256)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

데이터 베이스에 알려주고 적용하기

python manage.py makemigrations
python manage.py migrate
admin에 넣기
from django.contrib import admin
from .models import TweetModel

# Register your models here.
admin.site.register(TweetModel)

로그인 화면 띄우기

base, signup, signin html을 만들고 각각 이어줘야 한다.
sns에 있는 urls.py에는 user.urls에 있는 url들을 연결 시켜줘야 하고
user.urls는 views의 함수와 연결을 해줘야한다.
총 세가지의 작업이 필요.
sns에 있는 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')) #user앱의 urls.py에 연결시키겠다! 라고 선언 해 주는 코드 
]
유저의 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')
유저의 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'),
]
 

회원가입 기능 만들기

페이지 보여주기와 가입정보 입력 후 전송 url은 동일.
보여주는 것은 get방식, 데이터 전송은 post 방식
def sign_up_view(request):
    if request.method == 'GET': # GET 메서드로 요청이 들어 올 경우
        return render(request, 'user/signup.html')
    elif request.method == 'POST': # POST 메서드로 요청이 들어 올 경우
        
        return ""
signup.html에서 회원가입 시 데이터를 전송 할 수 있도록 수정해야함.
<!-- 윗 부분 생략 -->
<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">
            <label for="username">이름</label>
            <input type="text" class="form-control" id="username" name="username">
        </div>
        <div class="form-group mt-2 mb-2">
<!-- 아랫 부분 생략 -->
<form>태그의 가장 마지막에 있는 <button type="submit" class="btn btn-primary">회원가입</button> 버튼은, form태그의 method로 action에 데이터를 보내주는 역할
{% csrf_token %} 은, Django에서 post 할 때에 보안을 위해서 사용
회원가입 하면서 적었던 내용이 이제 post 방식으로 오게 되고, 그걸 db에 저장해야한다.
 
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')

로그인 기능 만들기

user.views에 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')
 
form태그에 method, action 추가하기.
아이디와 비밀번호 정보를 보내야 하기 때문.
 
<!-- 윗부분 생략 -->
<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에서 아이디와 비밀번호의 정보가 일치하는 유저가 있는지 확인
# 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')

# 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("로그인 성공!")
        else: # 로그인이 실패하면 다시 로그인 페이지를 보여주기
            return redirect('/sign-in')
    elif request.method == 'GET':
        return render(request, 'user/signin.html')
 
숙제 1: 아이디가 중복이라면 가입이 안되도록 코드 수정.
이거는 몰라서 바로 답안을 봤다. 필터를 배워야한다.
filter(조건 함수, 순회 가능한 데이터)
filter() 함수는 두번째 인자로 넘어온 데이터 중에서 첫번째 인자로 넘어온 조건 함수를 만족하는 데이터만을 반환합니다.
filter(조건 함수, 순회 가능한 데이터)
filter() 함수는 두번째 인자로 넘어온 데이터 중에서 첫번째 인자로 넘어온 조건 함수를 만족하는 데이터만을 반환합니다.
오오~~ 만약 조건 함수가 가입 시 id라면 순회 가능한 데이터가 모델의 id들로 한다면 중복을 찾아 낼 수 있겠구나!
 
숙제 2 : 로그인 시 로그인 id출력.
return HttpResponse(f"안녕하세요{username}님. 로그인 되었습니다.")
이거는 너무 쉬웠구.

'Django' 카테고리의 다른 글

장고 정리: 5주  (0) 2023.04.12
무신사 ERD  (0) 2023.04.09
파이썬 장고 실무 기초: 4  (0) 2023.04.05
파이썬 장고 실무 기초: 3  (0) 2023.04.05
파이썬 장고 실무 기초: 1  (0) 2023.04.03

마음가짐 : 오류나 에러가 나와도 침착하게 대처한다.

클라이언트 : 요청을 서버에 보낸다.

서버 : 요청을 받아서 응답을 해준다.

api : 데이터를 어떻게 주고 받자 라고 정한 약속. 데이터만 줄지, FE를 줄지, 둘다 줄지.

 

파이썬 문법: 데이터타입

변수 : 데이터를 담는 바구니
myname = 'bamtol'
등호로 구분한다.

 

숫자형 : 숫자가 변수 안에 들어가 있다.

mynum = 22
mynum2 = 22.8
사칙연산이 가능하다.
+, -, *, /
 

문자형 : 문자가 변수 안에 들어가 있다.

myheight = '180'
money = 'a lot'
큰 따옴표나 작은 따옴표로 꼭 감싸줘야한다.
문자열의 덧셈, 곱셈 가능.
문자열 기준으로 나누기도 가능
.split('@' ) (=@을 기준으로 리스트 형태로 나뉘어진다.)
 

리스트 : 하나의 변수에 여러개의 데이터를 나열 하듯 저장.

a= [1,2,3,4,5,6,7,8,9]
a[0] = 1
b = ['너' , '나']
b[1] = '나'
.append()로 리스트에 원소를 추가할 수 있다.

 

딕셔너리 : 대응 관계로 데이터를 나타내는 자료형)

dog = {'cute' : 'jindo' , 'alsocute' : 'mydog'}
dog['cute'] = 'jindo'
 

파이썬 문법 2 : 조건문과 반복문

들여쓰기를 지켜야 에러가 발생하지 않는다.
조건문 : 참과 거짓을 판단하는 문장.
if 조건:
	조건이 참일 경우 실행
else:
	조건이 거짓일 경우 실행
 
반복문 : 리스트와 같이 반복되는 곳에서 사용.
for 변수 in 리스트:
	실행 할 문장
파이썬 문법 3: 함수과 클래스
함수 : 인자들을 함수에 넣고 결과물을 내오는 것.
def 함수명('매개변수'):
	실행 할 문장들
클래스: 빵틀의 모양에 따라 만들어지는 빵의 모양이 다르다.(클래스의 속성)
객체 : 빵틀로 만들어진 빵.(클래스의 속성을 갖고 있는 객체)
class myBakery:
    title = ''
    time = ''
    taste = ''




cookie = myBakery()
cookie.title = '머핀'
cookie.time = '1h'
cookie.taste = '초콜릿'



print(cookie)
 

파이썬의 웹 프레임워크

프레임워크 : 개발을 도와주는 하나의 틀

최소한의 기능만 제공하는 형태

플라스크, 피라미드

많은 기능을 제공하는 형태

장고

장단점

최소한의 기능은 자유롭지만 많은 공부가 필요하고 커뮤니티가 작다.
장고는 이미 많이 만들어져 있고 틀에 따라야 하지만 또 만들 필요가 없고 커뮤니티가 크다.
 

장고 알아보기

MVT 패턴

Model : 데이터가 저장되고 사용되는 형태.
View : 서비스가 동작하는 부분. url요청 후 응답 그 사이에 일어나는 서비스들이 존재하는곳
Template : 사용자에게 보여지는 부분
 
ORM : 파이썬으로 데이터베이스 클래스 모델을 만들고, 모델을 바탕으로 데이터 베이스를 다룰 수 있도록 도와줌.
 

장고 프로젝트 만들기

새 프로젝트에서 장고를 선택해서 폴더를 확인하고 프로젝트를 만들면 된다.

settings.py 살펴보기

INSTALLED_APPS - 장고에 설치 된 앱들
MIDDLEWARE - 사용자 요청/응답 사이에서 작동하는 시스템들
TEMPLATES - 나의 html파일을 자동으로 인식
DATABASES - 내가 사용할 데이터베이스 연동 설정
AUTH_PASSWORD_VALIDATORS - 패스워드 보안 수준 검증
LANGUAGE_CODE - 화면에 어떤 언어를 보여줄것인지
TIME_ZONE - 우리가 어떤 시간에 있는지
 

장고를 사용한 화면 띄우기

 

인코딩 에러

실행 시 인코딩 에러가 난다면 설정에서 콘솔과 파일 인코딩을 utf-8로 바꾸어주면 해결이 된다.
 

글자 띄우기

views.py 만들고 코드 붙여 넣기
from django.http import HttpResponse





def base_response(request):
    return HttpResponse("안녕하세요! 장고의 시작입니다!")
HttpResponse()는 괄호 안에 있는 내용을 인터넷 창 화면에 보여주는 역할
(1) views.py에 글자를 띄우는 함수를 만들었다.
 
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'), # 이 줄 추가. 
]
(2) urls.py에 (1)에서 만든 함수를 불러올 수 있도록 url을 만들고 함수 이름을 추가했다.
 

html파일 띄우기

template 폴더에 my_test.html 파일을 만든다.
views.py에 코드를 추가한다. render 함수는 template에 있는 html 파일을 찾아서 보여준다.
from django.shortcuts import render



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'), # 이 줄 추가. 
]

'Django' 카테고리의 다른 글

장고 정리: 5주  (0) 2023.04.12
무신사 ERD  (0) 2023.04.09
파이썬 장고 실무 기초: 4  (0) 2023.04.05
파이썬 장고 실무 기초: 3  (0) 2023.04.05
파이썬 장고 실무 기초: 2  (0) 2023.04.04

+ Recent posts