python/Django
파라코드 기술설명서
- -
파라코드 기술설명서
✔️ 개요
💬 여러사람들이 다같이 채팅할수있고 1:1 채팅할수있는 커뮤니티 채팅사이트 구현
✔️ Github 리포지터리
✔️ 사용된기술
⚓️ 버전관리
- Git , Github
⚓️ 배포
- 👾 Github
- ☕️ Jenkins
- 🐳 Docker
♻️ 개발환경
- Anaconda
- Sqlyog
- Chrome
- Firefox
- Window 11
- PIP
🔥 서비스환경
- Nginx
- Mariadb
- Docker
- CentOS7
🔱 기술 스택
- Python 3
- Django 4
- Django MTV
- Django DRF
- MariaDB
- HTML,CSS,JS
- JQuery
- Tailwind
- Bootstrap
- daisy
✔️ 요구사항 현황
RQ-ID | 분류 | 요구사항내용 | 날짜 | 작성자 | 진행사항 |
---|---|---|---|---|---|
RQ-001 | 회원 | 회원가입 | 3/03 | 김채민 | ✔️ |
RQ-002 | 회원 | 로그인/로그아웃 | 3/03 | 김채민 | ✔️ |
RQ-003 | 회원 | 온/오프라인 상태 표시 | 3/03 | 김채민 | ✔️ |
RQ-004 | 회원 | 전체 유저 목록 | 3/03 | 김채민 | ✔️ |
RQ-005 | 회원 | 온라인 유저 목록 | 3/03 | 김채민 | ✔️ |
RQ-006 | 회원 | 유저 검색 | 3/03 | 김채민 | ✔️ |
RQ-007 | 회원 | 친구 추가 | 3/03 | 김채민 | ✔️ |
RQ-008 | 회원 | 친구 목록 | 3/03 | 김채민 | ✔️ |
RQ-101 | 채팅 | 단체 채팅 | 3/03 | 김채민 | ✔️ |
RQ-102 | 채팅 | 다이렉트 채팅 | 3/03 | 김채민 | ✔️ |
RQ-103 | 채팅 | 채팅방 생성 | 3/03 | 김채민 | ✔️ |
RQ-104 | 채팅 | 채팅방 나가기 | 3/03 | 김채민 | ✔️ |
RQ-105 | 채팅 | 채팅방 삭제 | 3/03 | 김채민 | ✔️ |
RQ-106 | 채팅 | 채팅방 목록 | 3/03 | 김채민 | ✔️ |
RQ-107 | 채팅 | 채팅방 검색 | 3/03 | 김채민 | ✔️ |
RQ-108 | 채팅 | 시스템 메시지 | 3/03 | 김채민 | ✔️ |
✔️ 기능
👤 회원
- 회원가입시 로그인 할수있는 회원이 만들어진다.
- 로그인시 회원으로 접속이 가능하다.
- 로그아웃이 된다.
- 온라인유저는 초록불, 오프라인유저는 빨간불 로 구별할수있다
- 친구 검색을 통해 친구를 검색할수있다
- 알림메세지를 통해 입 퇴장 메세지를 알려줄수있다
- 전체 회원을 보여줄수있다
- 친구 추가한 전체 친구목록을 보여줄수있다
- 전체 온라인 유저를 볼수있다
💬 채팅
- 채팅방만들기시 유저들과 채팅할수있는 채팅방을 만들수있다
- 채팅방나가기시 채팅방을 나갈수있다
- 채팅방검색을 통해 원하는 채팅방 을 찾을수있다
- 메인 아이콘을 을 통해 전체채팅방목록 을 볼수있다
- 단체채팅방을 만들어서 단체채팅을 할수있다
- 친구창에 다이렉트 메세지를 눌러 친구와 1:1 채팅 할수있다
- 시스템 메세지 구현을 통해 채팅방 입장 퇴장 알림메세지를 출력할수있다
✔️ ERD
✔️ 주요 폴더 및 파일
- accounts : 회원앱
- base : 프로젝트
- chat : 채팅앱
- static : 정적으로 발생하는 정적파일들을 담는 폴더
- requirement : 의존성 파일
- .env : 설정파일
- package.json : node 의존성
- nodemodules : node 패키지
- docker-compose.yaml : 가상컨테이너 오케스트레이션 파일
- dockerfile : Docker Image를 만들기 위한 설정 파일
- tailwind.config.js : 테일윈드 설정
🐳 배포 구조
- 커밋, 푸시, 젠킨스 빌드 유발, 컨테이너 내의 소스코드 리빌드
서버 구조
젠킨스 배포순서, 테스트 실패시
젠킨스 배포순서, 테스트 성공시
🔧 주요 기능 / 화면
▶️ 메인(로그인)
<!--base/tamplates/main.html-->
<div class="hero min-h-screen bg-base-200">
<div class="flex-col justify-center hero-content lg:flex-row">
<div class="text-center lg:text-left">
<i class="spin__icon fa-solid fa-feather-pointed fa-4x mb-8 duration-[30s]"></i>
<a href="{% url 'chat:list' %}">
<h1 class="mb-5 text-5xl font-bold text-green-400 finger-snapping-title duration-[30s]">
Paracord
</h1>
</a>
<p class="mb-5 finger-snapping-body duration-[30s]">
Provident cupiditate voluptatem et in. Quaerat fugiat ut
assumenda excepturi
</p>
</div>
<div
class="card flex-shrink-0 w-full max-w-sm shadow-2xl bg-base-100 ml-20"
>
<form
method="post"
class="post-form"
action="{% url 'accounts:login' %}"
>
{% csrf_token %}
<div class="card-body">
<div class="form-control">
<label class="label">
<span class="label-text">아이디</span>
</label>
<input
placeholder="아이디를 입력해주세요."
type="text"
class="form-control input input-bordered bg-gray-800"
name="username"
id="username"
value="{{ form.username.value|default_if_none:'' }}"
/>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">비밀번호</span>
</label>
<input
placeholder="비밀번호를 입력해주세요."
type="password"
class="form-control input input-bordered bg-gray-800"
name="password"
id="password"
value="{{ form.password.value|default_if_none:'' }}"
/>
</div>
<div class="d-flex justify-content-evenly mt-5">
<button class="btn btn-ghost bg-green-500 hover:bg-white hover:text-green-500">
로그인
</button>
<a
href="{% url 'accounts:signup' %}"
class="btn btn-ghost border-green-500 hover:bg-white hover:text-green-500"
>회원 가입</a
>
</div>
</div>
</div>
</div>
</div>
🔨 Tailwind와 Daisy Ui를 사용한 메인 페이지 HTML 코드
# base/urls.py
from django.contrib import admin
from django.urls import path, include
from django.contrib.auth import views as auth_views
urlpatterns = [
path('', auth_views.LoginView.as_view(template_name='main.html'), name='accounts'),
]
🔨 `url/`을 입력하면 main.html을 보여주는 path
▶️ 전체 채팅방 목록
<!--chat/templates/chat/room_list.html-->
<div class="m-24">
<h1
class="text-center text-4xl text-white m-10 text-gray-200 font-semibold"
>
Welcome to Paracord
</h1>
<h2 class="text-center mb-4">
파라코드에서는 여러 사람들이랑 소통할 수 있습니다
</h2>
<form action="{% url 'chat:list' %}" method="GET" class="text-center">
<input
name="kw"
type="text"
placeholder="채팅방 찾기"
class="p-4 text-lg rounded bg-gray-900 text-gray-200 w-4/5 h-12 py-2"
/>
<button class="-ml-24 text-lg bg-green-400 text-white rounded w-20">
검색하기
</button>
</form>
<div class="text-white grid grid-cols-4 gap-4 mt-12">
{% if rooms %} {% for room in rooms %}
<div
class="w-[80%] bg-gray-700 text-center border-gray-800 border rounded-[3%]"
>
<i class="fas fa-users fa-4x mt-10 mb-12"></i>
<div class="mb-10">
<div>{{ room.name }}</div>
<div class="mb-4 mt-4">
{% if room.part_server %}
<button class="bg-green-500 rounded-full w-32 text-lg">
<a href="{% url 'chat:detail' room.id %}">
서버 참가중
</a>
</button>
</div>
<div>
<button class="bg-red-500 rounded-full w-32 text-lg">
<a href="{% url 'chat:exit_server' room.id %}" onclick="if (confirm('정말 나가시겠습니까?') == false) return false;">
서버 나가기
</a>
</button>
{% else %}
<button class="bg-green-500 rounded-full w-32 text-lg">
<a href="{% url 'chat:access_server' room.id %}">
서버 참가
</a>
</button>
{% endif %}
</div>
</div>
</div>
{% endfor %} {% else %}
<h1>채팅방 is lonely...</h1>
{% endif %}
</div>
</div>
{% endblock %}
🔨 Tailwind와 Daisy Ui를 사용한 로그인 후 보이는 화면 HTML 코드
# chat/views.py
def room_list(request):
kw = request.GET.get('kw')
if kw:
rooms = Room.objects.filter(name__icontains=kw) | Room.objects.filter(name__startswith=kw)
if not rooms:
messages.error(request, "검색된 채팅방이 없습니다.")
else:
rooms = Room.objects.prefetch_related(
Prefetch('part_user', queryset=User.objects.filter(id=request.user.id), to_attr='part_server'))
rooms = rooms.exclude(room_type="direct")
users = User.objects.all()
context = {'rooms': rooms, 'users': users}
return render(request, 'chat/room_list.html', context)
🔨 모든 Room object를 받아와 HTML로 넘겨주는 python 코드 (kw는 채팅방 검색에서 이용된다.)
▶️ 채팅
단체 채팅
다이렉트 메세지 채팅
<!-- chat/templates/chat/room_detail.html -->
{% block app %}
{% include 'chat/js/chat_logic.html' %}
<div class="chat-messages text-gray-300" id="jax"></div>
{% endblock %}
🔨 chat_logic.html을 실행시켜 채팅 내용들을 받아오는 Tailwind를 사용한 HTML 코드
// chat/tamplates/chat/js/chat_logic.html
let ChickChat__lastMessageId = 0;
function ChickChat__loadMore() {
$.get(
"{% url 'chat:chat' room.id %}",
{
from_id: ChickChat__lastMessageId,
},
function (data) {
for (const chatKey in data.chats) {
const chat = data.chats[chatKey];
ChickChat__lastMessageId = chat.id;
ChickChat__renderMessage(chat);
}
console.log(1);
setTimeout(ChickChat__loadMore, 200);
},
"json"
);
}
let lastNickname = null;
let lastTimeStamp = null;
function ChickChat__renderMessage(chat) {
let chat_timestamp = moment(chat.timestamp).format("LT");
console.log(chat["m_type"]);
if (chat.m_type != "NOMAL") {
if (chat.m_type == "ENTER") {
$(".chat-messages").append(`
<div class="m-8">
<form class="bg-gray-800 text-center">
${chat.message}
<span class="text-gray-500 text-xs">
${chat_timestamp}
</span>
</form>
</div>`);
} else if (chat.m_type == "EXIT") {
$(".chat-messages").append(`
<div class="m-8">
<form class="bg-gray-800 text-center">
${chat.message}
<span class="text-gray-500 text-xs">
${chat_timestamp}
</span>
</form>
</div>`);
} else {
if (lastNickname != chat.nickname || lastTimeStamp != chat_timestamp) {
$(".chat-messages").append(`
<div class="flex-1 flex justify-between">
<div class="bg-gray-700 flex-1 flex flex-col justify-between">
<div class="text-sm overflow-y-auto">
<div class="flex mx-6 pt-3 mt-3 border-gray-500 border-t">
<div class="flex-none">
<i class="fas fa-user-circle fa-3x text-gray-400"></i>
</div>
<div class="ml-5">
<a class="text-white hover:underline text-sm">${chat.nickname}<a>
<span class="text-xs text-gray-500 ml-1">
${chat_timestamp}
</span>
<div>
<div class="mt-2">
${chat.message}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`);
} else {
$(".chat-messages").append(`
<div class="flex-1 flex justify-between">
<div class="bg-gray-700 flex-1 flex flex-col justify-between">
<div class="text-sm overflow-y-auto mt-1">
<div class="flex mx-6">
<div class="ml-[3em]">
<div class="ml-5">
${chat.message}
</div>
</div>
</div>
</div>
</div>
</div>
`);
}
lastNickname = chat.nickname;
lastTimeStamp = chat_timestamp;
}
}
console.log($("#chat_scroll").scrollTop($("#chat_scroll")[0].scrollHeight));
}
ChickChat__loadMore();
🔨 지속적으로 서버와 통신해(Ajax) 해당 채팅방의 채팅 오브젝트를 가져오는 js코드
# chat/views.py
def room_detail(request, room_id):
room = Room.objects.get(id=room_id)
room_detail = "True"
context = {'room': room, 'room_detail': room_detail}
return render(request, 'chat/room_detail.html', context)
🔨 url에 입력받은 room.id로 Room object를 찾아 html로 넘겨주는 python 코드
▶️ 채팅방 검색
)
<!--chat/templates/chat/room_list.html-->
<form action="{% url 'chat:list' %}" method="GET" class="text-center">
<input
name="kw"
type="text"
placeholder="채팅방 찾기"
class="p-4 text-lg rounded bg-gray-900 text-gray-200 w-4/5 h-12 py-2"
/>
<button class="-ml-24 text-lg bg-green-400 text-white rounded w-20">
검색하기
</button>
</form>
🔨 입력받은 kw(room.name)를 chat:list(views.py)로 넘겨주는 Tailwind를 사용한 html 코드
# chat/views.py
kw = request.GET.get('kw')
if kw:
rooms = Room.objects.filter(name__icontains=kw) | Room.objects.filter(name__startswith=kw)
if not rooms:
messages.error(request, "검색된 채팅방이 없습니다.")
else:
rooms = Room.objects.prefetch_related(
Prefetch('part_user', queryset=User.objects.filter(id=request.user.id), to_attr='part_server'))
🔨 입력받은 kw에 해당되는 Room objects가 있으면 objects를 list로 넘겨주고, 없다면 안내메시지를 넘겨주는 python 코드
▶️ 채팅방 검색 (Modal)
<!--chat/templates/chat/modal/serch_room_modal.html-->
<label
for="my-modals-2"
class="modal_button cursor-pointer flex items-center justify-center overflow-hidden whitespace-nowrap w-14 h-14 mx-auto mt-3 text-green-400 transition-all hover:duration-[300ms] bg-gray-700 rounded-[50%] hover:text-white hover:bg-teal-500 hover:rounded-[30%] modal-button"
>
<i class="fa-solid fa-magnifying-glass"></i>
</label>
<input type="checkbox" id="my-modals-2" class="modal-toggle" />
<div class="modal">
<div class="modal-box flex justify-center">
<form action="{% url 'chat:list' %}" method="GET" class="text-center">
{% csrf_token %}
<input
name="kw"
type="text"
placeholder="채팅방 찾기"
class="p-4 text-lg rounded bg-gray-900 text-gray-200 h-12 py-1 w-[16em]"
/>
<label for="my-modals-2" class="btn btn-ghost bg-green-500 hover:bg-white hover:text-green-500"> 검색하기 </label>
<label for="my-modals-2" class="btn close-are">취소</label>
</form>
</div>
</div>
🔨 버튼 클릭 시 kw(room.name)를 입력받는 input 창을 출력하는 Tailwind, Daisy Ui를 사용한 HTML 코드(Modal)
# chat/views.py
kw = request.GET.get('kw')
if kw:
rooms = Room.objects.filter(name__icontains=kw) | Room.objects.filter(name__startswith=kw)
if not rooms:
messages.error(request, "검색된 채팅방이 없습니다.")
else:
rooms = Room.objects.prefetch_related(
Prefetch('part_user', queryset=User.objects.filter(id=request.user.id), to_attr='part_server'))
🔨 입력받은 kw에 해당되는 Room objects가 있으면 objects를 list로 넘겨주고, 없다면 안내메시지를 넘겨주는 python 코드
▶️ 채팅방 생성 (Modal)
<!--chat/templates/chat/modal/create_room_modal.html-->
<label
for="my-modal-2"
class="cursor-pointer flex items-center justify-center overflow-hidden whitespace-nowrap w-14 h-14 mt-3 mx-auto text-green-400 transition-all hover:duration-[300ms] bg-gray-700 rounded-[50%] hover:text-white hover:bg-teal-500 hover:rounded-[30%]"
>
<i class="fas fa-plus fa-1x"></i>
</label>
<input type="checkbox" id="my-modal-2" class="modal-toggle hidden" />
<div class="modal">
<div class="modal-box flex justify-center">
<form method="post" action="{% url 'chat:create' %}">
{% csrf_token %}
<input
name="name"
type="text"
placeholder="채팅방 생성"
class="p-4 text-lg rounded bg-gray-900 text-gray-200 h-12 py-1 w-[16em]"
/>
<label for="my-modal-2" class="btn btn-ghost bg-green-500 hover:bg-white hover:text-green-500">생성하기</label>
<label for="my-modal-2" class="btn">취소</label>
</form>
</div>
</div>
🔨 버튼 클릭 시 name(room.name)을 입력받는 input 창을 출력하는 Tailwind, Daisy Ui를 사용한 HTML 코드(Modal)
# chat/views.py
@login_required(login_url='accounts:login')
def room_create(request):
if request.method == "POST":
form = RoomForm(request.POST)
if form.is_valid():
room = form.save(commit=False)
room.host = request.user
room.reg_date = timezone.now()
room.save()
request.user.part_server.add(room)
messages.success(request, f"{room.name} 채팅방이 생성되었습니다.")
return redirect('chat:detail', room_id=room.id)
else:
messages.error(request, "이미 존재하는 채팅방 이름입니다.")
else:
messages.error(request, "정상적이지 않은 접근입니다.")
return redirect('chat:list')
return redirect(request.META.get('HTTP_REFERER'))
🔨입력받은 room.name으로 room object를 생성하고 해당 채팅방으로 이동 시켜주는 python 코드 / room.name이 없거나, 중복되는 room.name이 있다면 에러 메시지를 출력한다.
▶️ 채팅방나가기
🔨 Modal 을 이용하여 다른페이지로가는 불편함을 없애고 바로 방을나갈수있다
▶️ 시스템메세지
🔨 단체채팅방에서 시스템 메세지를 통해 입/퇴장 메시지를 출력한다.
▶️ 유저 검색
<!--accounts/templates/friend_search.html-->
{% extends 'layout.html' %} {% block content %}
<div class="ml-8 mt-4 mb-2 text-white text-lg">친구 추가하기</div>
<div class="ml-8 mb-6">
Paracord 닉네임을 입력하시면 친구추가를 할수있어요.
</div>
<form
action="{% url 'accounts:searching_user' %}"
method="GET"
class="text-center"
>
<input
name="kw"
type="text"
placeholder="사용자명"
class="p-4 text-lg rounded bg-gray-900 text-gray-200 w-4/5 h-12 py-2"
/>
<button
class="-ml-24 text-lg bg-green-400 text-white rounded w-20"
>
검색하기
</button>
</form>
<div class="border-b mt-10 border-gray-600"></div>
<div class="text-white">
<div class="ml-8 mt-4 mb-2 text-white text-lg">찾은 유저</div>
{% if find_friend %}
<div class="ml-8 mb-6 text-gray-400">
친구를 찾았어요! 친구추가 버튼을 누르면 우린 친구!
</div>
{% for i in find_friend %}
<br />
<div
class="hover:rounded ml-24 bg-gray-700 hover:bg-gray-600 w-4/5 border-b border-gray-500 text-white flex justify-between"
>
<button class="mt-4 mb-4 flex">
{% if i.is_active == 0 %}
<i class="fas fa-circle text-red-600"></i>
<div class="ml-8">{{i.nickname}}</div>
{% else %}
<div>
<i class="fas fa-circle text-green-400 mt-1"></i>
</div>
<div class="ml-8">
{{i.nickname}} {% if user == i %}
<span class="bg-gray-700">[본인]</span>
{% endif %}
</div>
{% endif %}
</button>
<a href="{% url 'accounts:add_friend' i.id %}">
<button class="bg-green-500 rounded w-14 mt-4">친구추가</button>
</a>
</div>
{% endfor %} {% else %}
<div class="ml-8 mb-6 text-gray-400">
검색된 친구가 없어요.. 외롭네요ㅠㅠ
</div>
{% endif %}
</div>
{% endblock %}
🔨 kw(user.nickname)를 입력받는 input 창을 출력하는 Tailwind, Daisy Ui를 사용한 HTML 코드
# accounts/views.py
def searching_user(request):
kw = request.GET.get('kw')
find_friend = User.objects.filter(nickname__icontains=kw) | User.objects.filter(nickname__startswith=kw)
return render(request, 'friend_search.html', {'find_friend': find_friend})
🔨 입력받은 kw에 해당되는 user object를 찾아 html로 넘겨주는 python 코드
▶️ 모든 유저 목록
<!--accounts/templates/all_user_list.html-->
{% extends 'layout.html' %}
{% block content %}
<div class="text-gray-200 mx-4 mt-2 h-12 my-4 ">
<div class="ml-4 mt-4 mb-2 text-white text-lg">
모든유저
</div>
<div class="text-gray-400 ml-4 mb-6 ">
Paracord 모든 유저 목록이에요!
</div>
</div>
{% for use in users %}
<br>
<div class="hover:rounded ml-24 bg-gray-700 hover:bg-gray-600 w-4/5 border-b border-gray-500 text-white flex justify-between">
<button class="mt-4 mb-4 flex">
{% if use.is_active == 0 %}
<i class="fas fa-circle text-red-600"></i>
<div class="ml-8">
{{use.nickname}}
</div>
{% else %}
<div>
<i class="fas fa-circle text-green-400 mt-1"></i>
</div>
<div class="ml-8">
{{use.nickname}}
{% if user == use %}
<span class="bg-gray-700">[본인]</span>
{% endif %}
</div>
{% endif %}
</button>
<a href="{% url 'accounts:add_friend' use.id %}">
<button class="bg-green-500 rounded w-14 mt-4 ">친구추가</button>
</a>
</div>
{% endfor %}
{% endblock %}
🔨user objects를 출력하는 Tailwind, Daisy Ui를 사용한 HTML 코드
# accounts/views.py
def user_list_all(request):
users = User.objects.all()
context = {'users': users}
return render(request, 'all_user_list.html', context)
🔨 모든 user object를 HTML로 넘겨주는 python 코드
▶️ 친구 목록
<!--accounts/templates/friend_list.html-->
{% extends 'layout.html' %} {% block content %}
<div class="text-gray-200 mx-4 mt-2 h-12 my-4">
<div class="ml-6 mt-4 mb-2 text-white text-lg">친구</div>
<div class="text-gray-400 ml-6 mb-6">나의 친구들이에요!</div>
</div>
<div class="ml-10 mt-8">
<div id="tooltip-default" role="tooltip" class="inline-block invisible z-10 py-1 px-3 -ml-[33px] text-sm font-medium text-white bg-gray-900 rounded-lg shadow-sm opacity-0 transition-opacity duration-300 tooltip dark:bg-gray-700 ">
다이렉트 메시지
<div class="tooltip-arrow -ml-1" data-popper-arrow></div>
</div>
{% for friend in user.friends.all %}
<button class="hover:rounded ml-20 bg-gray-700 hover:bg-gray-600 w-3/4 mt-6 border-b border-gray-500 flex justify-between">
<div class="flex mt-4">
<div class="ml-4 text-gray-300 mb-2">
<i class="fas fa-user-circle fa-2x"></i>
</div>
<div class="ml-4 text-white text-sm y-4 m-0 mt-1">{{friend}}</div>
</div>
<a
class="w-10 h-10 bg-gray-800 rounded-full mt-1 z-9 mr-4"
href="{% url 'chat:create_dm' friend.nickname %}"
data-tooltip-target="tooltip-default"
>
<i class="far fa-envelope fa-lg bg-gray-700 mt-5"></i>
</a>
</button>
<form action=""></form>
{% endfor %}
</div>
{% endblock %}
🔨 로그인 유저의 friends 필터에 존재하는 user object를 출력하는 Tailwind, Daisy Ui를 사용한 HTML 코드
# accounts/views.py
def user_list(request):\
return render(request, 'friend_list.html')
🔨friend_list.html로 이동시키는 python 코드
▶️ 온라인 유저 목록
<!--accounts/templates/online_user_list.html-->
{% extends 'layout.html' %}
{% block content %}
<div class="ml-8 mt-4 mb-2 text-white text-lg">
온라인
</div>
<div class="text-gray-400 ml-8 mb-2">
온라인 상태인 사람들이예요!
</div>
{% for use in users %}
<br>
<div
class="hover:rounded ml-24 bg-gray-700 hover:bg-gray-600 w-4/5 border-b border-gray-500 text-white flex justify-between">
<button class="mt-4 mb-4 flex">
{% if use.is_active == 0 %}
<i class="fas fa-circle text-red-300"></i>
<div class="ml-20">
{{use.nickname}}
</div>
{% else %}
<div>
<i class="fas fa-circle text-green-400 mt-1"></i>
</div>
<div class="ml-8">
{{use.nickname}}
{% if user == use %}
<span class="bg-gray-700">[본인]</span>
{% endif %}
</div>
{% endif %}
</button>
<a href="{% url 'accounts:add_friend' use.id %}">
<button class="bg-green-500 rounded w-14 mt-4 ">친구추가</button>
</a>
</div>
{% endfor %}
{% endblock %}
🔨user objects를 출력하는 Tailwind를 사용한 HTML 코드
# accounts/views.py
def user_list_online(request):
users = User.objects.filter(is_active=1)
context = {'users': users}
return render(request, 'online_user_list.html', context)
🔨모든 user object 중 is_active값이 1인 object만 필터링하여 HTML로 넘겨주는 python 코드
⚙ 기능 테스트
👬 회원
- ✅회원가입 : 2022-02-23
- ✅로그인 : 2022-02-23
- ✅로그아웃 : 2022-02-23
- ✅로그인 로그아웃 상태 표시 : 2022-02-23
- ✅유저 검색 : 2022-02-23
- ✅안내 메시지 : 2022-02-23
- ✅모든 회원 리스팅 : 2022-02-23
- ✅모든 친구 리스팅 : 2022-02-23
- ✅모든 온라인 유저 리스팅 : 2022-02-23
💻 채팅
- ✅채팅방 만들기 : 2022-02-23
- ✅채팅방 나가기 : 2022-02-23
- ✅채팅방 삭제 : 2022-02-23
- ✅채팅방 찾기 : 2022-02-23
- ✅단체 채팅 : 2022-02-23
- ✅다이렉트 메세지 채팅 : 2022-02-23
- ✅친구찾기 : 2022-02-23
- ✅친구추가 : 2022-02-23
- ✅시스템 메시지 추가 : 2022-02-23
- ✅모든 채팅방 리스팅 : 2022-02-23
- ✅내가 참가중인 채팅방 리스팅 : 2022-02-23
- ✅내가 만든 채팅방 리스팅 : 2022-02-23
반응형
Contents
소중한 공감 감사합니다