프로젝트 구조
먼저 사용자를 관리하는 앱을 만들것이다.
먼저 터미널에
django-admin startapp 앱이름
을 입력하면 해당이름을 가진 앱폴더가 생겨난다
(user이라는 이름으로 생성함)
다음으로는 이 앱을 추가했다는걸 settigs에 적어서 알려줘야 한다.
내부에 보면 상단에 이런식으로 되어있을거다.
똑같이 생성한 앱의 이름을 넣어주면된다.
주석으로 적혀있는걸 보니 앱들을 어떻게 정의하고 django가 이를통해 인지할건지에 대한 것같다.
이와같이 settings파일 안에는 django와 관련된 모든 세팅이 들어있는데 내리다보면
이렇게 DB설정이 들어가있는걸 확인할수 있다.
python manage.py runserver
로 서버를 실행해보자
정상적으로 잘 작동이 됨가 더불어
이렇게 프젝폴더와 manage.py사이에 db.sqlite3
라는 파일이 생성된걸 알 수있다.
여기서 pycham과 vscode의 DB를 확인하는 방법은 다르다.
필자는vs코드를 이용했으므로 그에 대한방법을 적겠다.
먼저 확장프로그램을 설치해주면 되는데
요 SQLite라는놈을 설치해주고
db파일에 우클릭하고 Open Database를 누르면
아래에 SQLITE EXPLORER이 생기면서 구조를 확인할수 있다.
이제 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)
간단하게 구조를 살펴보자면
각각 username는 유저이름, password 비밀번호, bio 상태정보 created_at은 생성일, updated_at은 수정일이다.
이를 Meta클래스로 한번 더 감쌌는데 db에 정보를 넣어주는 역할을 한다.
이제 만든 이 UserModel을 db에 넣어줄 차례다
그전에는 계속 migrattion이 안되었다고 징징대는 모습을 볼 수 있는데
먼저
python manage.py makemigrations
로 변경되었다고 알려주고
python manage.py migrate
로 db에 자동으로 생성하게 해줄것이다.
그 뒤에 먼저 SQLITE EXPLORER의 오른쪽상단에 새로고침을 눌러주면
요런식으로 아까는 없었던 뭐가 막 생긴걸 확인할 수 있다.
만약에 만약에 실수로 그 창을 꺼버린다면
(이러한 탐색기들은 독립적으로 위치를 변경할수있는데 혼자 다른곳에 가면 창을 닫을수있게 X가 있어서 못참고 눌러버린...)
F1을 누르고 SQLite Explorer 보기에 포커스
를 찾아 눌러주면 간단히 해결된다.
admin설정
다음은 admin설정이다
먼저 admin으로 로그인할 정보를 입력해주자
py manage.py createsuperuser
터미널에 입력하면 다음과 같이 뜨는데
(여태 모든 명령어 앞의 python은 py로 줄여도 무관하다)
사용할 아이디, 이메일, 비번을 입력하면 되는데 테스트용이라 대충적었더니 비번이 이름이랑 똑같고 8자리를 꼭 넘어야하며 너무 흔하다고 잔소리를 하지만 무시해도 무관하다
y를 입력하면 그대로 넘어간다(Bypass)
그러고 admin페이지로 가면
(주소는 항상 접속하던 그 로컬주소뒤에 /admin입력)
이렇게 뜨는데..엄...뭔가 좀 깨져보이지만 괜찮다
아까 설정한 로그인정보를 입력해보자
이렇게 넘어가서
Users를 클릭했을때
admin정보가 뜨면 성공
그리고 user앱도 이곳에 등록해줄수도 있다.
users에 admin.py에 가서
from django.contrib import admin
from .models import UserModel
# Register your models here.
admin.site.register(UserModel)
이 내용을 넣어주고 새로고침하면
잘 들어간걸 확인할 수 있다.
앱을 하나 더 만들어주자
글을 쓸수있는 앱을 만들것이다
만들었다면 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)
이와같이 기능을 하도록 넣어주고
여기서 author은 우리가 만들었던 User Model의 사용자가 작성 한 글이기에 ForeignKey를 사용해 넣었다
ForeignKey는 외부 모델을 가져와서 사용하는 역할이다
맨처음 settings에 적어준것처럼 'tweet'
을 추가해주자
그 뒤에 동일하게 마이그레이션해주고
admin에 넣어주고 서버를 다시 실행하면
잘 뜬다.
그리고 여기서 오류 하나
이렇게 맨 끝에 뭐라뭐라하면서 이미 있다라고 하는 경우가 있다.
이는 현재
이런식으로 tweet앱에 들어갈 이름 중복되어 들어간 경우인데 이거땜에 30분은 고민했던것 같다.
로그인 페이지 만들기
먼저 templates폴더 안에 base.html을 만들어준다
앞으로 사용할 html의 말 그대로 기본이라고 생각하면 된다.
그리고 user라는 폴더를 생성해 그 하위에 signup.html, signin.html이 두 파일을 생성해 준다
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %} | spartaSNS</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-eOJMYsd53ii+scO/bJGFsiCZc+5NDVN2yr8+0RDqr0Ql0h+rP48ckxlpbzKgwra6" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-JEW9xMcG8R+pH31jmWH6WWP0WintQrMb4s7ZOdauHnUtxwoG2vI5DkLtS3qm9Ekf"
crossorigin="anonymous"></script>
<style>
.title-center {
text-align: center;
margin-top: 50px;
}
.wrap {
width: 400px;
margin: 0 auto;
}
.form-area {
margin-top: 25px;
}
.timeline-container {
margin-top : 25px
}
</style>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<a class="navbar-brand" href="/">SpartaSNS</a>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#"> 친구 <span class="sr-only"></span></a>
</li>
</ul>
</div>
<form class="form-inline my-2 my-lg-0">
<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>
</form>
</div>
</nav>
{% block content %}
{% endblock %}
</body>
</html>
대충 이런식으로 내용을 넣어는데 여기서 저 {% block content %}
, {% endblock %}
이 둘은 다른 파일에서 불러와 채우겠다. 즉, 이 안의 내용은 바꿀수 있다.
그렇게 해당 안에 들어갈 내용은
먼저 signin.html
{% extends 'base.html' %}
{% block title %}
로그인
{% endblock %}
{% block content %}
<div class="container">
<div class="wrap">
<h2 class="title-center">
로그인</h2>
<form class="form-area">
<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">
<label for="password">비밀번호</label>
<input type="password" class="form-control" id="password" name="password">
</div>
<hr>
<div style="float: right">
<button type="submit" class="btn btn-primary">로그인</button>
<a href="/sign-up" class="btn btn-secondary">회원가입 페이지로</a>
</div>
</form>
</div>
</div>
{% endblock %}
signup.html
{% extends 'base.html' %}
{% block title %}
회원가입
{% endblock %}
{% block content %}
<div class="container">
<div class="wrap">
<h2 class="title-center">회원가입</h2>
<form class="form-area">
<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">
<label for="password">비밀번호</label>
<input type="password" class="form-control" id="password" name="password"/>
</div>
<div class="form-group mt-2 mb-2">
<label for="password2">비밀번호 확인</label>
<input type="password" class="form-control" id="password2" name="password2"/>
</div>
<div class="form-group mt-2 mb-2">
<label for="bio">나를 한마디로</label>
<input type="text" class="form-control" id="bio" name="bio"/>
</div>
<hr/>
<div style="float: right">
<button type="submit" class="btn btn-primary">회원가입</button>
<a href="/sign-in" class="btn btn-secondary">로그인 페이지로</a>
</div>
</form>
</div>
</div>
{% endblock %}
여기서 중요한것 한가지
만약 확장프로그램으로 prettier을 사용하고 있다면 제대로 작동이 안할수도 있다
이런식으로 끝부분인 {% endblock %}
을 강조하며 못찾겠다고 이상하다고 뭐라 할것이다
이는 오토포맷터인 prettier가
이런식으로 자동개행을 넣어버려 코드인식이 안된다는 것이다
그래서 django 전용 포맷터인 unibeauty를 설치해줘야 한다
그러면
예쁘게 잘 되며 페이지도 정상작동할 것이다
그전에 페이지를 연결해야겠지
장고가 돌아가는 구조는 대충 이런식인데
이제 view와 url을 작성해서 이어주어야 한다
먼저 user폴더의 views파일에
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')
이렇게 user폴더에 이런 파일들이 있으니 render. 즉, 보여달라 라고 함수를 만들고 이들을
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'),
]
이런식으로 추가해준다
현재 디렉토리의 views안에 각각 함수이름별로 부르는것이다.
그리고 메인폴더에 있는 urls.py에 이들을 연결해줬다고 적어줘야 한다.
from django.urls import path, include
이런식으로 include
를 추가하고
urlpatterns 리스트 안에
path('', include('user.urls')),
를 추가해주자
(signup페이지)
(signin페이지)
이와같이 정상적으로 뜨는것을 볼 수있다
이제 이들을 작동하게 하려면 몇가지를 더 만져줘야 한다.
GET으로 할거냐 POST로 할거냐로 설정해주는데 GET은 읽어오기, POST는 입력, 삭제와 같은 요청을 할때 사용한다
그 내용들을 각각 views.py에 넣은 함수에서 수정해줄건데
from django.shortcuts import render, redirect
from .models import UserModel
from django.http import HttpResponse
# Create your views here.
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 HttpResponse("중복닉임")
else:
new_user = UserModel()
new_user.username = username
new_user.password = password
new_user.bio = bio
new_user.save()
return redirect('/sign-in')
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(f"{me.username}님 로그인 성공!")
else:
return redirect('/sign-in')
elif request.method == 'GET':
return render(request, 'user/signin.html')
(views.py 전체코드)
살펴보자면 GET메소드로 요청이 들어올경우 보고있는 페이지를 그대로 보여준다. 즉, 잘못입력해서 POST가 안되었으니 다시 입력해라 정도로 보면 된다.
만약 POST로 넘어갔을 경우에는 각각 post로 request한것들을 db에 담는다.
다음 if문에서는 비밀번호검증을 한다
두번 입력을 하는데 이 둘이 다를경우에는 다시 페이지를 로드해준다
그 밑의 else는 이미 있는 닉네임과 같을경우 '중복닉임'이라는 문구가 나오는 페이지를 보여주는 형식이다
맞으면 else로 넘어가는데 새로 입력받아서 저장하고 sign-in즉 로그인 페이지로 넘어가게 된다.
그 아래 로그인에 대한것을 보자
로그인 버튼을 누른다. 즉 POST메소드가 실행되면 그 입력받은 내용들을 me에 담아주고(사용자를 불러옴) 여기서 비밀번호가 맞는지 검증을 하는데 맞으면 user세션에 사용자 이름을 저장하고 '로그인 성공!'이라는 메시지가 보이는 페이지로 넘어가고 로그인에 실패하면 다시 로그인페이지를 보여준다
이제 이 각각 GET과 POST메소드를 연결해주어야 한다.
html파일로 가서
(signin.html)
메소드를 post로 설정해주고 action을 sign-in으로 해준다
바로 이 작동을 하게해주는것이 버튼인데 form을 실행시켜주는 역할을 한다
(sigup.html)
이것또한 이렇게 수정해 준다.
여기까지 회원가입과 로그인기능이 완성되었다.
그래서 이 데이터는 어디로 가느냐
SQLite로 보는 이 탐색기에서 my_user을 찾아 오른쪽 화살표를 클릭하면
이렇게 뜨게 된다
django는 이런식으로 소통한다
정말 말 그대로 프레임워크라 그런지 그냥 python으로 서버를 열어서 mongodb로 데이터를받고 하는것보다 훨씬 간단하고 편하다
끝