장고 기초 2

godo·2022년 5월 7일
0

Django

목록 보기
2/2
post-thumbnail

방 갯수에 관련된 코드

 {% for topic in topics %}
<div>

    <a href="{% url 'home' %}?q={{topic.name}}">{{topic.name}}</a>
</div>
{% endfor %}

폼 만들기

자동

{% for field in form %}

     <div class="form__group">
     <label for="room_name">{{field.label}}</label>
      <!-- <input id="room_name" name="room_name" type="text" placeholder="E.g. Mastering Python + Django" /> -->
      {{field}}
      </div>
{% endfor %}

매뉴얼하게

템플릿

<div class="form__group">
    <label for="room_topic">Topic</label>
    <input required type="text" name="topic" list="topic-list">
     <datalist id="topic-list">
      <select id="room_topic">
      {% for topic in topics %}
      <option value="{{topic.name}}">{{topic.name}}</option>
      {% endfor %}
      </select>
     </datalist>
</div>
            

<div class="form__group">
      <label for="room_name">Name</label>
      {{form.name}}
</div>


<div class="form__group">
      <label for="room_description">Room Description</label>
      {{form.description}}
</div>

뷰파일에서

topics = Topic.objects.all()

context = {'form': form,'topics':topics}

이렇게 하면 자동 완성 및 옵션 기능 가능

@login_required(login_url='login')
def createRoom(request) : 
    form = RoomForm()
    topics = Topic.objects.all()
    if request.method == 'POST' :
        topic_name = request.POST.get('topic')
        topic, created = Topic.objects.get_or_create(name=topic_name)

        Room.objects.create(
            host=request.user,
            topic = topic,
            name = request.POST.get('name'),
            description = request.POST.get('description'),
        )
        
        return redirect('home') # url 에 이름 있어서 redirect 가능해짐

    context = {'form':form,'topics':topics}
    return render(request, 'base/room_form.html', context)

최종 (뷰,템플릿 파일에서)

@login_required(login_url='login')
def createRoom(request) : 
    form = RoomForm()
    topics = Topic.objects.all()
    if request.method == 'POST' :
        topic_name = request.POST.get('topic')
        topic, created = Topic.objects.get_or_create(name=topic_name)

        Room.objects.create(
            host=request.user,
            topic = topic,
            name = request.POST.get('name'),
            description = request.POST.get('description'),
        )
     
        return redirect('home') # url 에 이름 있어서 redirect 가능해짐

    context = {'form':form,'topics':topics}
    return render(request, 'base/room_form.html', context)


@login_required(login_url='login')
def updateRoom(request,pk) : 
    room = Room.objects.get(id=pk)
    form = RoomForm(instance=room)
    topics = Topic.objects.all()

    if request.user != room.host : 
        return HttpResponse('Your are not allowed here!!!')

    if request.method == 'POST' :

        topic_name = request.POST.get('topic')
        topic, created = Topic.objects.get_or_create(name=topic_name)
        room.topic = topic
        room.name = request.POST.get('name')
        room.description = request.POST.get('description')
        room.save()
        return redirect('home')

    context = {'form': form,'topics':topics,'room':room}
    return render(request, 'base/room_form.html',context)
 <div class="form__group">
              <label for="room_topic">Enter a topic</label>
              <input required type="text" value="{{room.topic.name}}" name="topic" list="topic-list">
              <datalist id="topic-list">
                <select id="room_topic">
                  {% for topic in topics %}
                  <option value="{{topic.name}}">{{topic.name}}</option>
                  {% endfor %}
                </select>
              </datalist>
            </div>
            

            <div class="form__group">
              <label for="room_name">Name</label>
              {{form.name}}
            </div>


            <div class="form__group">
              <label for="room_description">Room Description</label>
              {{form.description}}
            </div>

update user

템플릿

{% extends 'main.html' %}

{% block content %}
    <main class="update-account layout">
        <div class="container">
            <div class="layout__box">
                <div class="layout__boxHeader">
                    <div class="layout__boxTitle">
                        <a href="{% url 'home' %}">
                            <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32"
                                viewBox="0 0 32 32">
                                <title>arrow-left</title>
                                <path
                                    d="M13.723 2.286l-13.723 13.714 13.719 13.714 1.616-1.611-10.96-10.96h27.625v-2.286h-27.625l10.965-10.965-1.616-1.607z">
                                </path>
                            </svg>
                        </a>
                        <h3>Edit your profile</h3>
                    </div>
                </div>
                <div class="layout__body">
                    <form class="form" action="#" method="POST">
                      {% csrf_token %}
                        <div class="form__group">
                            <label for="profile_pic">Avatar</label>
                            <input id="profile_pic" name="profile_pic" type="file" />
                        </div>


      
                        <div class="form__action">
                            <a class="btn btn--dark" href="index.html">Cancel</a>
                            <button class="btn btn--main" type="submit">Update</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
      </div>
    </main>
{% endblock %}

자세히 ...

{% for field in form %}
                        <div class="form__group">
                            <label for="profile_pic">{{field.label}}</label>
                            {{field}}
                        </div>
                        {% endfor %}

입력 폼

class UserForm(ModelForm) :
    class Meta :
        model = User 
        fields = ['username','email']

뷰 파일

@login_required(login_url='login')
def updateUser(request) :
    user = request.user
    form = UserForm(instance=user)

    if request.method == 'POST' :
        form = UserForm(request.POST, instance=user)
        if form.is_valid() :
            form.save()
            return redirect('user-profile', pk=user.id)

    return render(request, 'base/update-user.html',{'form':form})

삭제 페이지


{% extends 'main.html' %}

{% block content %}

    <main class="delete-item layout">
        <div class="container">
            <div class="layout__box">
                <div class="layout__boxHeader">
                    <div class="layout__boxTitle">
                        <a href="{{request.META.HTTP_REFERER}}">
                            <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32"
                                viewBox="0 0 32 32">
                                <title>arrow-left</title>
                                <path
                                    d="M13.723 2.286l-13.723 13.714 13.719 13.714 1.616-1.611-10.96-10.96h27.625v-2.286h-27.625l10.965-10.965-1.616-1.607z">
                                </path>
                            </svg>
                        </a>
                        <h3>Back</h3>
                    </div>
                </div>
                <div class="layout__body">
                    <form class="form" method="POST" action="#">
                        {% csrf_token %}
                        <div class="form__group">
                            <p>Are you sure you want to delete "{{obj}}"?</p>
                        </div>

                        <div class="for__group">
                            <input class="btn btn--main" type="submit" value="Confirm" />
                        </div>

                    </form>
                </div>
            </div>
        </div>
    </main>
{% endblock content %}

로그인 페이지

{% extends 'main.html' %}

{% block content %}
    <main class="auth layout">

      {% if page == 'login' %}
      <div class="container">
        <div class="layout__box">
          <div class="layout__boxHeader">
            <div class="layout__boxTitle">
              <h3>Login</h3>
            </div>
          </div>
          <div class="layout__body">
            <h2 class="auth__tagline">Find your study partner</h2>

            <form class="form" action="#" method="POST">
              {% csrf_token %}
              <div class="form__group form__group">
                <label for="room_name">Username</label>
                <input id="username" name="username" type="text" placeholder="e.g. dennis_ivy" />
              </div>
              <div class="form__group">
                <label for="password">Password</label>
                <input
                  id="password"
                  name="password"
                  type="password"
                  placeholder="&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;"
                />
              </div>

              <button class="btn btn--main" type="submit">
                <svg
                  version="1.1"
                  xmlns="http://www.w3.org/2000/svg"
                  width="32"
                  height="32"
                  viewBox="0 0 32 32"
                >
                  <title>lock</title>
                  <path
                    d="M27 12h-1v-2c0-5.514-4.486-10-10-10s-10 4.486-10 10v2h-1c-0.553 0-1 0.447-1 1v18c0 0.553 0.447 1 1 1h22c0.553 0 1-0.447 1-1v-18c0-0.553-0.447-1-1-1zM8 10c0-4.411 3.589-8 8-8s8 3.589 8 8v2h-16v-2zM26 30h-20v-16h20v16z"
                  ></path>
                  <path
                    d="M15 21.694v4.306h2v-4.306c0.587-0.348 1-0.961 1-1.694 0-1.105-0.895-2-2-2s-2 0.895-2 2c0 0.732 0.413 1.345 1 1.694z"
                  ></path>
                </svg>

                Login
              </button>
            </form>

            <div class="auth__action">
              <p>Haven't signed up yet?</p>
              <a href="{% url 'register' %}" class="btn btn--link">Sign Up</a>
            </div>
          </div>
        </div>
      </div>
    {% else %}
    <div class="container">
      <div class="layout__box">
        <div class="layout__boxHeader">
          <div class="layout__boxTitle">
            <h3>Login</h3>
          </div>
        </div>
        <div class="layout__body">
          <h2 class="auth__tagline">Find your study partner</h2>

          {% for field in form %}
          <form class="form" action="#" method="POST">
            {% csrf_token %}
            <div class="form__group form__group">
              <label for="room_name">{{field.label}}</label>
              {{field}}
            </div>
          {% endfor %}

            <button class="btn btn--main" type="submit">
              <svg
                version="1.1"
                xmlns="http://www.w3.org/2000/svg"
                width="32"
                height="32"
                viewBox="0 0 32 32"
              >
                <title>lock</title>
                <path
                  d="M27 12h-1v-2c0-5.514-4.486-10-10-10s-10 4.486-10 10v2h-1c-0.553 0-1 0.447-1 1v18c0 0.553 0.447 1 1 1h22c0.553 0 1-0.447 1-1v-18c0-0.553-0.447-1-1-1zM8 10c0-4.411 3.589-8 8-8s8 3.589 8 8v2h-16v-2zM26 30h-20v-16h20v16z"
                ></path>
                <path
                  d="M15 21.694v4.306h2v-4.306c0.587-0.348 1-0.961 1-1.694 0-1.105-0.895-2-2-2s-2 0.895-2 2c0 0.732 0.413 1.345 1 1.694z"
                ></path>
              </svg>

              Register
            </button>
          </form>

          <div class="auth__action">
            <p>Haven't signed up yet?</p>
            <a href="{% url 'register' %}" class="btn btn--link">Sign Up</a>
          </div>
        </div>
      </div>
    </div>
    </main>
    {% endif %}
  {% endblock content %}

템플릿

<ul class="topics__list">
      <li>
       <a href="{% url 'topics' %}" class="active">All <span>{{topcis.count}}</span></a>
      </li>
      {% for topic in topics %}
      <li>
       <a href="/">{{ topic.name }} <span>{{topic.room_set.all.count}}</span></a>
       </li>
      {% endfor %}
</ul>
 <li>
     <a href="{% url 'topics' %}" class="active">All <span>{{topcis.count}}</span></a>
</li>
      {% for topic in topics %}
      <li>
      <a href="{% url 'home' %}?q={{topic.name}}">{{ topic.name }} <span>{{topic.room_set.all.count}}</span></a>
      </li>
{% endfor %}

검색

뷰 파일

def topicsPage(request) :
    q = request.GET.get('q') if request.GET.get('q') != None else ''
    topics = Topic.objects.filter(name__icontains=q)
    return render(request, 'base/topics.html', {'topics':topics})

템플릿

<form action="" method="GET" class="header__search">
              <label>
                <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
                  <title>search</title>
                  <path
                    d="M32 30.586l-10.845-10.845c1.771-2.092 2.845-4.791 2.845-7.741 0-6.617-5.383-12-12-12s-12 5.383-12 12c0 6.617 5.383 12 12 12 2.949 0 5.649-1.074 7.741-2.845l10.845 10.845 1.414-1.414zM12 22c-5.514 0-10-4.486-10-10s4.486-10 10-10c5.514 0 10 4.486 10 10s-4.486 10-10 10z"
                  ></path>
                </svg>
                <input name="q" placeholder="Search for topics" />
              </label>
</form>

옆에 토픽 수 제한

home 함수에 가서

topics = Topic.objects.all()[:5]

activity page

템플릿

<a class="btn btn--main btn--pill" href="{% url 'activity' %}">Recent Activities</a>


뷰 파일

def activityPage(request) :
    room_messages = Message.objects.all()
    return render(request, 'base/activity.html', {})

url 파일

path('activity/', views.activityPage, name="activity"),

결론, 뷰 파일

def activityPage(request) :
   room_messages = Message.objects.all()
   return render(request, 'base/activity.html', {'room_messages':room_messages})

결론, 템플릿 파일

{% extends 'main.html' %}

{% block content %}
    <main class="layout">
      <div class="container">
        <div class="layout__box">
          <div class="layout__boxHeader">
            <div class="layout__boxTitle">
              <a href="{% url 'home' %}">
                <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
                  <title>arrow-left</title>
                  <path
                    d="M13.723 2.286l-13.723 13.714 13.719 13.714 1.616-1.611-10.96-10.96h27.625v-2.286h-27.625l10.965-10.965-1.616-1.607z"
                  ></path>
                </svg>
              </a>
              <h3>Recent Activities</h3>
            </div>
          </div>

          <div class="activities-page layout__body">

            {% for message in room_messages %}
    <div class="activities__box">
      <div class="activities__boxHeader roomListRoom__header">
        <a href="{% url 'user-profile' message.user.id %}" class="roomListRoom__author">
          <div class="avatar avatar--small">
            <img src="https://randomuser.me/api/portraits/women/11.jpg" />
          </div>
          <p>
            @{{message.user}}
            <span>{{message.created|timesince}} days ago</span>
          </p>
        </a>

        {% if request.user == message.user %}
        <div class="roomListRoom__actions">
          <a href="{% url 'delete-message' message.id %}">
            <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
              <title>remove</title>
              <path
                d="M27.314 6.019l-1.333-1.333-9.98 9.981-9.981-9.981-1.333 1.333 9.981 9.981-9.981 9.98 1.333 1.333 9.981-9.98 9.98 9.98 1.333-1.333-9.98-9.98 9.98-9.981z"
              ></path>
            </svg>
          </a>
        </div>
        {% endif %}
      </div>
      <div class="activities__boxContent">
        <p>replied to post “<a href="{% url 'room' message.room.id %}">{{message.room}}</a></p>
        <div class="activities__boxRoomContent">
            {{message.body}}
        </div>
      </div>
      
    </div>
    {% endfor %}
  
          </div>
        </div>
      </div>
    </main>

{% endblock %}

REST Framework

폴더 및 파일 만들기

views.py

from django.http import JsonResponse

def getRoutes(request) :
    routes = [
        'GET /api',
        'GET /api/rooms',
        'GET /api/rooms/:id',
    ]
    return JsonResponse(routes, safe=False) 

urls.py

import django


from django.urls import path
from . import views


urlpatterns = [
    path('', views.getRoutes),
    
]

프로젝트 파일 urls.py 에 가서

urlpatterns = [
    path('admin/', admin.site.urls),
    path('',include('base.urls')),
    path('api/', include('base.api.urls'))
 
]

문서

https://www.django-rest-framework.org/

가서 설치

pip install djangorestframework

# settings.py 가서 

INSTALLED_APPS = [
    ...
    'rest_framework',
]

뷰 파일 변경

from rest_framework.decorators import api_view
from rest_framework.response import Response

@api_view(['GET'])
def getRoutes(request) :
    routes = [
        'GET /api',
        'GET /api/rooms',
        'GET /api/rooms/:id',
    ]
    return Response(routes) 

이런식으로 화면이 뜸

room 데이터 주기

뷰파일

from base.models import Room


@api_view(['GET'])
def getRooms(request) :
    rooms = Room.objects.all()
    return Response(rooms)

url 파일

path('api/', include('base.api.urls'))

... 그러니 리스트 형태여서 오류가 남

리스트 > 시리얼라이즈 , serializers.py

from rest_framework.serializers import ModelSerializer
from base.models import Room



class RoomSerializer(ModelSerializer) : 
    class Meta: 
        model = Room
        fields = '__all__'

뷰파일

from .serializers import RoomSerializer


@api_view(['GET'])
def getRooms(request) :
    rooms = Room.objects.all()
    serializer = RoomSerializer(rooms,many=True) # multiple object 인지 
    return Response(serializer.data)

방 하나 하나 마다

  • 뷰 파일
@api_view(['GET'])
def getRoom(request,pk) :
    rooms = Room.objects.get(id=pk)
    serializer = RoomSerializer(rooms,many=False) # multiple object 인지 
    return Response(serializer.data)
    
  • url 파일
path('rooms/<str:pk>',views.getRoom),

사용해 보기

python -m pip install django-cors-headers

...
https://pypi.org/project/django-cors-headers/
여기 문서 보면서 cors headers 관련 오류 찾기

INSTALLED_APPS = [
    ...,
    "corsheaders",
    ...,
]


MIDDLEWARE = [
    ...,
    "corsheaders.middleware.CorsMiddleware",
    ...,
]


CORS_ALLOW_ALL_ORIGINS = True 

이러면 돌아감

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Cool Rooms</title>
</head>
<body>

    <h1>Cools Rooms</h1>

    <div id="rooms-container"></div>
    
</body>

<script>
    let getRooms = async () => {
        let response = await fetch('http://127.0.0.1:8000/api/rooms/')
        console.log('RESPONSE:', response)
    }

    getRooms()

</script>

</html>

그리고

<script>
    let getRooms = async () => {
        let response = await fetch('http://127.0.0.1:8000/api/rooms/')
        let rooms = await response.json()
        console.log('rooms:', rooms)
    }

    getRooms()

</script>

console 창 가면 데이터를 받아 온 것을 볼 수 있음

최종 html 파일

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Cool Rooms</title>
</head>
<body>

    <h1>Cools Rooms</h1>

    <div id="rooms-container"></div>
    
</body>

<script>

    let roomsContainer = document.getElementById('rooms-container') 

    let getRooms = async () => {
        let response = await fetch('http://127.0.0.1:8000/api/rooms/')
        let rooms = await response.json()
        console.log('rooms:', rooms)

        for(let i=0; i<rooms.length ; i++) {
            let room = rooms[i]
            let row = `<div><h3>${room.name}</h3></div>`

            roomsContainer.innerHTML += row
        }

    }

    getRooms()

</script>

</html>

Custom User Model

setting.py

installed_app 에 
'base.app.BaseConfig',


AUTH_USER_MODEL = 'base.User'

이거 추가

models.py

from django.db import models

from django.contrib.auth.models import AbstractUser


class User(AbstractUser) :
    pass

makemigrations , migrate ...

admin

createsuperuser 하고

admin.py 가서

from .models import User 

admin.site.register(User)

해주기

그리고 어드민 페이지에서 체크

customizing 로그인 창 및 정보 필드

모델 파일

from django.contrib.auth.models import AbstractUser


class User(AbstractUser) :
    name = models.CharField(max_length=200, null=True)
    email = models.EmailField(unique=True)
    bio = models.TextField(null=True)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

이러면 이메일로 로그인 가능하고 여러가지 필드 관련해서 만들 수 있음

중간에 모델 변경하기

  • 먼저 sqlite3 파일 삭제
  • migrations 내부에 있던 모델 관련 파일 싹다 없애기

뷰 파일


from django.db import models
from django.contrib.auth.models import AbstractUser


class User(AbstractUser) :
    pass 

세팅 파일

AUTH_USER_MODEL = 'base.User'

어드민 파일에 등록

admin.site.register(User)

파일 변경

from django.contrib.auth.models import User
  • 이 부분 뷰와 폼 파일에서 삭제

모델 적용

class User(AbstractUser) :
    name = models.CharField(max_length=200, null=True)
    email = models.EmailField(unique=True)
    bio = models.TextField(null=True)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

이미지 필드

서버 끄고

python3 -m pip install pillow

그리고 다시 서버 키기

모델 변경

avatar = models.ImageField(null=True, default="avatar.svg")

세팅 파일

MEDIA_URL = '/images/'

STATICFILES_DIRS = [
    BASE_DIR / 'static'
]

url 파일

from django.conf import settings
from django.conf.urls.static import static

... 

urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

feed component에서

이미지 테그 찾아서

<img src="{{room.host.avatar.url}}" />

와 같이 변경

<img src="{{request.user.avatar.url}}" />

room

<img src="{{room.host.avatar.url}}" />

<img src="{{message.user.avatar.url}}" />

나머지는 이와 같이 계속 해서 진행 됨

정보 입력 .. 이미지 추가

forms.py 에

from django.contrib.auth.forms import UserCreationForm

class UserForm(ModelForm) :
    class Meta :
        model = User 
        fields = ['avatar','name','username','email','bio']

같은 코드를 입력

업데이트 템플릿에 가서

<form class="form" action="#" method="POST" enctype="multipart/form-data">

다양한 폼 넘겨준다는 의미

뷰 파일

@login_required(login_url='login')
def updateUser(request) :
    user = request.user
    form = UserForm(instance=user)

    if request.method == 'POST' :
        form = UserForm(request.POST, request.FILES , instance=user) # 주어진 파일 
        if form.is_valid() :
            form.save()
            return redirect('user-profile', pk=user.id)

    return render(request, 'base/update-user.html',{'form':form})

회원가입 폼

폼 파일

class MyUserCreationForm(UserCreationForm) :
    class Meta : 
        model = User
        fields = ['name','username','email','password1','password2']

뷰파일

# from django.contrib.auth.forms import UserCreationForm
# 이부분 제거 
 
from .forms import RoomForm, UserForm ,MyUserCreationForm
# 추가
 

UserCreationForm >> MyUserCreationForm

def registerPage(request) : 
    page = 'register'
    form = MyUserCreationForm()

    if request.method == 'POST' : 
        form = MyUserCreationForm(request.POST)
        if form.is_valid() : 
            user = form.save(commit=False) # 전처리 
            user.username = user.username.lower() # 대문자 소문자로 처리
            user.save()
            login(request,user)      
            return redirect('home')
        else : 
            messages.error(request, 'An error occured during registration')

    return render(request, 'base/login_register.html',{'form':form})

로그인 폼

템플릿

<div class="form__group form__group">
      <label for="room_name">Email</label>
      <input id="username" name="email" type="text" placeholder="e.g. dennis_ivy" />
</div>

뷰 파일

def loginPage(request) :
    page ='login'

    if request.user.is_authenticated : 
        return redirect('home')

    if request.method == 'POST' : 
        email = request.POST.get('email').lower() 
        password = request.POST.get('password')

        try:
            user = User.objects.get(email=email)
        except:
            messages.error(request, 'User does not exist')
        
        user = authenticate(request,email=email, password=password)

        if user is not None : 
            login(request, user)
            return redirect('home')
        
        else : 
            messages.error(request, 'Username OR password does not exit')

username 부분을 email 로 바꾸기

profile
☀️☀️☀️

0개의 댓글