www.acmicpc.net/problem/15649

 

15649번: N과 M (1)

한 줄에 하나씩 문제의 조건을 만족하는 수열을 출력한다. 중복되는 수열을 여러 번 출력하면 안되며, 각 수열은 공백으로 구분해서 출력해야 한다. 수열은 사전 순으로 증가하는 순서로 출력해

www.acmicpc.net

def dfs(depth, N, M):
    if depth == M:
        print(' '.join(map(str, out)))
        return

    # 전체를 탐색 1,2,3,4
    for i in range(N):
        # 아직 방문하지 않았다면
        if not visited[i]:
            visited[i] = True   # 방문 처리
            out.append(i+1)     # 방문 기록
            dfs(depth+1, N, M)      # 깊이 우선 탐색
            visited[i] = False  # 방문 기록 제거
            out.pop()


N,M = map(int, input().split())
visited = [False] * N
out = []
dfs(0,N,M)

'Algorithm' 카테고리의 다른 글

트리 자료구조 - 이진 탐색 트리  (0) 2021.04.16
이진탐색(Binary Search)  (0) 2021.04.16
BOJ - 18870번 - 좌표 압축  (0) 2021.04.08
BOJ - 11651번 - 좌표 정렬하기 2  (0) 2021.04.08
BOJ - 11650번 - 좌표 정렬하기  (0) 2021.04.08

어떠한 클래스(객체가) 유일하게 1개만 존재 할 경우에 사용

주로 사용되는 곳은 서로 자원을 공유 할 때 사용

ex) 프린터, TCP Socket 통신에서 서버와 연결된 connect 객체, Spring의 bean

 

Singleton
instance
singleton()
getInstance()

- 실습

 

// SocketClient.java 

package com.company.gof.singleton;

public class SocketClient {

    private static SocketClient socketClient = null;

    private SocketClient(){

    }

    public static SocketClient getInstance(){

        if(socketClient == null){
            socketClient = new SocketClient();
        }
        return socketClient;
    }

    public void connect(){
        System.out.println("connect");
    }
}

 

//A.java

package com.company.gof.singleton;

public class A {
    private SocketClient socketClient;

    public A(){
        this.socketClient = SocketClient.getInstance();
    }

    public SocketClient getSocketClient(){
        return this.socketClient;
    }
}

//B.java

package com.company.gof.singleton;

public class B {

    private SocketClient socketClient;

    public B(){
        this.socketClient = SocketClient.getInstance();
    }

    public  SocketClient getSocketClient(){
        return this.socketClient;
    }
}

 

 

//main.java

package com.company.gof;

import com.company.gof.singleton.A;
import com.company.gof.singleton.B;
import com.company.gof.singleton.SocketClient;

public class Main {

    public static void main(String[] args) {
	// write your code here
        A a = new A();
        B b = new B();

        SocketClient aClient = a.getSocketClient();
        SocketClient bClient = b.getSocketClient();

        System.out.println("두개의 객체가 동일한가?");
        System.out.println(aClient.equals(bClient));

    }
}

 

-결과

'Spring' 카테고리의 다른 글

Decorator pattern(데코레이터 패턴)  (0) 2021.04.18
Proxy pattern(프록시 패턴)  (0) 2021.04.16
Adapter pattern(어댑터 패턴)  (0) 2021.04.16
디자인 패턴  (0) 2021.04.15
POJO 클래스  (0) 2021.04.15

자주 사용하는 설계 패턴을 정형화 시켜서 이를 유형별로 가장 최적의 방법으로 개발 할 수 있도록 설계둔 설계

알고리즘과 유사하나, 무조건적인 정답은 아니며, 프로젝트 상황에 맞춰 적용한다.

 

#Gof 디자인 패턴

SW 설계를 할 때 기존의 경험이 매우 중요한데, 모든 사람들이 많은 경험을 다 가지고 있을 수 는 없다.

따라서 이러한 지식을 공유하기 위해서 나온 것이 GOF(Gang of Four) 디자인 패턴이다.

객체 지향의 개념 중 재사용에 대한 설계를 할때 유용한 디자인 패턴을 정리 해두었다.

 

Gof의 디자인 패턴은 총 23개 이고, 이것을 활용하면 경험이 부족한 개발자도 좋은 SW 설계가 가능하다.

 

▶︎장점

• 소프트웨어 구조 파악 용이     •재사용으로 인한 개발 시간 단축

• 개발자간 원활한 소통             • 설계 변경 요청에 대한 유연한 대처

 

▶︎단점

• 객체지향 설계 / 구현 •초기 투자 비용 부담

 

- 생성 패턴:

객체를 생성하는 것과 관련된 패턴으로, 객체의 생성과 변경이 전체 시스템에 미치는 영향을 최소화, 코드의 유연성을 높여줌

  • Factory Method
  • Singleton
  • Prototype
  • Builder
  • Abstract Factory
  • Chaining

-구조 패턴:

프로그램 내의 자료구조나 인터페이스 구조 등 프로그램 구조를 설계하는데 활용 될 수 있는 패턴

큰 규모의 시스템에서는 많은 클래스들이 서로 의존성을 가지게 되는데, 이런 복잡한 구조를 개발하기 쉽게 만들어 주고, 유지 보수를 쉽게 만들어 줌

 

  • Adapter
  • Composite
  • Bridge
  • Decorator
  • Facade
  • Flyweight
  • Proxy

- 행위 패턴: 

반복적으로 사용되는 객체들의 상호작용을 패턴화한 것으로, 행위 관련 패턴을 사용하여 독집적으로 일을 처리하고자 할 때 사용.

  • Template Method
  • Interpreter
  • Iterator
  • Observer
  • Strategy
  • Visitor
  • Chain of responsibility
  • Command
  • Mediator
  • State
  • Memento

 

'Spring' 카테고리의 다른 글

Decorator pattern(데코레이터 패턴)  (0) 2021.04.18
Proxy pattern(프록시 패턴)  (0) 2021.04.16
Adapter pattern(어댑터 패턴)  (0) 2021.04.16
Singleton pattern(싱글톤 패턴)  (0) 2021.04.15
POJO 클래스  (0) 2021.04.15

순수한 자바 클래스로써

 

1. 특정 규약에 종속 되지 않는다.

특정 Library, Module 에서 정의된 클래스를 상송 받아서 구현하지 않아도 된다.

POJO가 되지 위해서는 외부 의존성을 두지 않고, 순수한 JAVA로만 구성이 가능해야 한다.

 

2. 특정 환경에 종속되지 않는다.

비즈니스 로직에 작성 하는 부분에 외부 종속적인 httrp request 등은 POJO를 위반한 것이고.,

혹은 요즘 많이 사용하고 있는 @Annotation 방식도 Dependency에서 JPA를 제거하면 바로 에러가 뜨기 때문에 엄연히 POJO 클래스라고 할 수 없다.

 

#Spring, Hibernate

두 프레임워크에서 객체지향적인 설계를 지향하며, POJO클래스를 지향하고 있다

프레임워크들은 개발자가 시스템의 복잡함에 대한 부담감을 덜어 주고, 서비스 로직에 집중하며 POJO 지향적인 코딩을 할 수 있게 도와준다.

'Spring' 카테고리의 다른 글

Decorator pattern(데코레이터 패턴)  (0) 2021.04.18
Proxy pattern(프록시 패턴)  (0) 2021.04.16
Adapter pattern(어댑터 패턴)  (0) 2021.04.16
Singleton pattern(싱글톤 패턴)  (0) 2021.04.15
디자인 패턴  (0) 2021.04.15

장고에서는 로그인, 로그아웃 등과 같은 로직에 대한 기능들이 이미 settings.py에 앱으로 등록되어 있어 이것을 활용하면 간편하게 로그인, 로그아웃, 회원가입까지 구현할 수 있다.

# Application definition

INSTALLED_APPS = [
    'django.contrib.auth',
]

로그인, 로그아웃과 같은 기능들은 하나의 프로젝트 안에서 다른 앱들도 공용으로 사용될 여지가 충분하기 때문에 하나의 앱안에 기능을 구현하는 것은 부적절하다. 그렇기 때문에 common과 같은 앱을 따로 생성하여 다른 앱들과 공용으로 사용할 수 있게 구성한다.

 

1. common 앱 생성

django-admin startapp common

 

2. settings.py에 생성한 앱 등록

INSTALLED_APPS = [
    #생략
    'common.apps.CommonConfig',

]

3. project/urs.py 경로 추가

urlpatterns = [
   #생략
    path('common/',include('common.urls'))
]

 

3. common/urls.py

from django.urls import path
from django.contrib.auth import views as auth_views
from . import views
app_name = 'common'

urlpatterns = [
    path('login/', auth_views.LoginView.as_view(template_name='common/login.html'),name='login'),
    path('logout/', auth_views.LogoutView.as_view(),name='logout'),
    path('signup/', views.signup, name='signup'),
]

4. common/forms.py 회원가입 폼 만들기

from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User


class UserForm(UserCreationForm):
    email = forms.EmailField(label="이메일")

    class Meta:
        model = User
        fields = ("username", "email")

 

 

5..common/views.py

from django.contrib.auth import authenticate, login
from django.shortcuts import render, redirect

# Create your views here.

# 계정생성
from common.forms import UserForm


def signup(request):
    if request.method == "POST":
        form = UserForm(request.POST)
        if form.is_valid():
            form.save()
            username = form.cleaned_data.get('username')
            raw_password = form.cleaned_data.get('password1')
            user = authenticate(username=username, password = raw_password)
            login(request,user)
            return redirect('index')
    else:
        form = UserForm()
    return render(request, 'common/signup.html', {'form': form})

 

6. 템플릿 파일 생성

 

# common/login.html

{% extends "base.html" %}
{% block content %}
<div class="container my-3">
<!-- ------------------------------- 로그인 타이틀 , 회원가입 버튼 -------------------------------- -->
    <div class="row">
        <div class="col-4">
            <h4>로그인</h4>
        </div>
        <div class="col-8 text-right">
            <span>또는 <a href="{% url 'common:signup' %}">계정을 만드세요.</a></span>
        </div>
    </div>
<!-- ----------------------------------------------------------------------- -->
    <form method="post" class="post-form" action="{% url 'common:login' %}">
        {% csrf_token %}
        {% include "common/form_errors.html" %}
        <div class="form-group">
            <label for="username">사용자ID</label>
            <input type="text" class="form-control" name="username" id="username"
                   value="{{ form.username.value|default_if_none:'' }}">
        </div>
        <div class="form-group">
            <label for="password">비밀번호</label>
            <input type="password" class="form-control" name="password" id="password"
                   value="{{ form.password.value|default_if_none:'' }}">
        </div>
        <button type="submit" class="btn btn-primary">로그인</button>
    </form>
</div>
{% endblock %}

 

# form_errors.html

{% if form.errors %}
    {% for field in form %}
        {% for error in field.errors %}  <!-- 필드 오류를 출력한다. -->
            <div class="alert alert-danger">
                <strong>{{ field.label }}</strong>
                {{ error }}
            </div>
        {% endfor %}
    {% endfor %}
    {% for error in form.non_field_errors %}   <!-- 넌필드 오류를 출력한다. -->
        <div class="alert alert-danger">
            <strong>{{ error }}</strong>
        </div>
    {% endfor %}
{% endif %}

# signup.html

{% extends "base.html" %}
{% block content %}
<div class="container my-3">
    <div class="row my-3">
        <div class="col-4">
            <h4>계정생성</h4>
        </div>
        <div class="col-8 text-right">
            <span>또는 <a href="{% url 'common:login' %}">로그인 하세요.</a></span>
        </div>
    </div>
    <form method="post" class="post-form">
        {% csrf_token %}
        {% include "common/form_errors.html" %}
        <div class="form-group">
            <label for="username">사용자 이름</label>
            <input type="text" class="form-control" name="username" id="username"
                   value="{{ form.username.value|default_if_none:'' }}">
        </div>
        <div class="form-group">
            <label for="password1">비밀번호</label>
            <input type="password" class="form-control" name="password1" id="password1"
                   value="{{ form.password1.value|default_if_none:'' }}">
        </div>
        <div class="form-group">
            <label for="password2">비밀번호 확인</label>
            <input type="password" class="form-control" name="password2" id="password2"
                   value="{{ form.password2.value|default_if_none:'' }}">
        </div>
        <div class="form-group">
            <label for="email">이메일</label>
            <input type="text" class="form-control" name="email" id="email"
                   value="{{ form.email.value|default_if_none:'' }}">
        </div>
        <button type="submit" class="btn btn-primary">생성하기</button>
    </form>
</div>
{% endblock %}

 

7. 로그인, 로그아웃 후 리다이렉트 처리하기

# settings.py (홈으로 이동)

LOGIN_REDIRECT_URL = '/'
LOGOUT_REDIRECT_URL = '/'

 

 

출처: wikidocs.net/book/4223 (점프 투 장고)

 

- 게시판 임시 데이터 만들기

 

#파이썬 쉘 진입 및 라이브러리 추가

>python manage.py shell
# 파이썬 쉘 진입
>>> from pybo.models import Question
>>> from django.utils import timezone  

 

#반복문을 이용하여 데이터 삽입

>>> for i in range(300):
...    q = Question(subject='테스트 데이터:[%03d]' % i, content='컨텐츠 내용', create_date=timezone.now())
...    q.save() 
...    
>>>

 

# ListView를 이용한 간단한 페이징 구현 (project/main/views.py)

class index(ListView):
    model = Question
    # 템플릿 파일 지정
    template_name = 'main/index.html'
    # 화면에 표시될 데이터의 개수
    paginate_by = 10

	# 추가로 보낼 데이터
    def get_context_data(self, **kwargs):
        context = super(index, self).get_context_data()
        context['page_title'] = '질문과 답변'
        return context
	# request를 받으면 실행되는 Query
    def get_queryset(self):
        return self.model.objects.order_by('-create_date')

❖ paginate_by = 한 페이지에 보여질 데이터 개수 로 값을 설정하면 한 페이지에 대한 데이터들은 기본적으로 page_obj라는 변수에 들어가게 된다.

 

# 템플릿 구현 (project/main/templates/index.html)

{% extends 'base.html' %}
{% load custom_filter %}
{% block page_title %} {{ page_title }} {% endblock %}
{% block content %}
    <div class="container my=3">
    <table class="table">
        <thead>
        <tr class="thead-dark">
            <th>번호</th>
            <th>제목</th>
            <th>작성일시</th>
        </tr>
        </thead>
        <tbody>
        {% if page_obj %}
            {% for question in page_obj %}
                <tr>
                    <td>{{ paginator.count }}</td>
                    <td>
                        <a href="{% url 'main:detail' question.id %}">{{ question.subject }}</a>
                        {% if question.answer_set.count > 0 %}
                            <span class="text-danger small ml-2">{{ question.answer_set.count }} </span>
                        {% endif %}
                    </td>
                    <td>{{ question.create_date }}</td>
                </tr>
            {% endfor %}
        {% else  %}
            <tr>
                <td colspan="3">질문이 없습니다.</td>
            </tr>
        {% endif %}
        </tbody>
    </table>
    <!-- page nav -->
    <ul class="pagination justify-content-center">
       <!-- 이전 페이지-->
        {% if page_obj.has_previous %}
        <li class="page-item">
            <a class="page-link" href="?page={{ page_obj.previous_page_number }}">이전</a>
        </li>
        {% else %}
        <li class="page-item disabled">
            <a class="page-link" tabindex="-1" aria-disabled="true" href="#">이전</a>
        </li>
        {% endif %}
        <!-- 페이지 리스트 -->
        {% for page_number in paginator.page_range %}
        {% if page_number == page_obj.number %}
            <li class="page-item active" aria-current="page">
                <a class="page-link" href="?page={{ page_number }}">{{ page_number }}</a>
            </li>
            {% else %}
            <li class="page-item">
                <a class="page-link" href="?page={{ page_number }}">{{ page_number }}</a>
            </li>
            {% endif %}

        {% endfor %}
        <!-- 다음 페이지 -->
        {% if page_obj.has_next %}
        <li class="page-item">
            <a class="page-link" href="?page={{ page_obj.next_page_number }}">다음</a>
        </li>
        {% else %}
        <li class="page-item disabled">
            <a class="page-link" tabindex="-1" aria-disabled="true" href="#">다음</a>
        </li>
        {% endif %}
    </ul>
    <a href="{% url 'main:question_create' %}" class="btn btn-primary">질문 등록</a>
    </div>
{% endblock %} #}

 

 

- 결과 화면

 

☑︎ 문제점

• 1. 각 페이지 번호가 1~10로 고정 되어 있는 점

• 2. 페이지 번호가 너무 많아져 정상적으로 표기가 안되는 점

 

# 사용자 지정 템플릿 필터 만들기 (sub: 빼기 연산을 위한 필터)

1. 템플릿 필터 폴더 만들기: 템플릿 폴더와 같은 위치에 templatetags 폴더 생성

2. filter.py 생성

from django import template

register = template.Library()


@register.filter
def sub(value, arg):
    return value - arg

 

3. 적용할 템플릿 상단에 {% load 'filter 파일명' %} 작성

 

{% extends 'base.html' %}
{% load custom_filter %}
{% block page_title %} {{ page_title }} {% endblock %}
{% block content %}
    <div class="container my=3">
    <table class="table">
        <thead>
        <tr class="thead-dark">
            <th>번호</th>
            <th>제목</th>
            <th>작성일시</th>
        </tr>
        </thead>
        <tbody>
        {% if page_obj %}
            {% for question in page_obj %}
                <tr>
                	<!-- 1. 문제점 해결책 각 페이지 번호 -->
                    <!-- 번호 = 전체 건수 - 시작인덱스 - 현재인덱스 +1 -->
                    <td>{{ paginator.count | sub:page_obj.start_index|sub:forloop.counter0|add:1 }}</td>
                    <td>
                        <a href="{% url 'main:detail' question.id %}">{{ question.subject }}</a>
                        {% if question.answer_set.count > 0 %}
                            <span class="text-danger small ml-2">{{ question.answer_set.count }} </span>
                        {% endif %}
                    </td>
                    <td>{{ question.create_date }}</td>
                </tr>
            {% endfor %}
        {% else  %}
            <tr>
                <td colspan="3">질문이 없습니다.</td>
            </tr>
        {% endif %}
        </tbody>
    </table>
    <!-- page nav -->
    <ul class="pagination justify-content-center">
       <!-- 이전 페이지-->
        {% if page_obj.has_previous %}
        <li class="page-item">
            <a class="page-link" href="?page={{ page_obj.previous_page_number }}">이전</a>
        </li>
        {% else %}
        <li class="page-item disabled">
            <a class="page-link" tabindex="-1" aria-disabled="true" href="#">이전</a>
        </li>
        {% endif %}
        <!-- 페이지 리스트 -->
        {% for page_number in paginator.page_range %}
        <!-- 2. 문제점 해결 페이지 버튼 수 조정 -->
        <!-- 페이지 수 조정 -->
        {% if page_number >= page_obj.number|add:-5 and page_number <= page_obj.number|add:5 %}
            {% if page_number == page_obj.number %}
            <li class="page-item active" aria-current="page">
                <a class="page-link" href="?page={{ page_number }}">{{ page_number }}</a>
            </li>
            {% else %}
            <li class="page-item">
                <a class="page-link" href="?page={{ page_number }}">{{ page_number }}</a>
            </li>
            {% endif %}
        {% endif %}
        {% endfor %}
        <!-- 다음 페이지 -->
        {% if page_obj.has_next %}
        <li class="page-item">
            <a class="page-link" href="?page={{ page_obj.next_page_number }}">다음</a>
        </li>
        {% else %}
        <li class="page-item disabled">
            <a class="page-link" tabindex="-1" aria-disabled="true" href="#">다음</a>
        </li>
        {% endif %}
    </ul>
    <a href="{% url 'main:question_create' %}" class="btn btn-primary">질문 등록</a>
    </div>
{% endblock %} #}

 

- 결과 화면

 

 

 

출처: wikidocs.net/book/4223 (점프 투 장고)

프로젝트의 전반적인 설정을 담당하는 곳은 settings.py 이고 각 앱마다 필요한 항목의 대한 설정을 할 수 있는 곳은 apps.py 파일이다.

장고 공식 문서를 보면 apps.py 파일의 용도로 앱 이름에 대한 별칭(verbose_name)을 정의하거나 시그널(signal) 수신자를 등록하는 예시를 보여주고 있다.

 

현재 실습하고 있는 polls, books 라는 앱 이름을 하드코딩하고 있는데 apps.py를 활용하면 이 부분을 개선할 수 있다.

3가지 파일(apps.py, view.py, 템플릿 파일)을 수정한다.

 

- app.py

from django.apps import AppConfig


class BooksConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'books'
    verbose_name = 'Book-Author-Publisher App' #추가

 

- views.py

# views.py
from django.http import  HttpResponse
from django.views.generic import TemplateView
from django.apps import apps

class HomeView(TemplateView):
    template_name = "home.html"

    def get_context_data(self, **kwargs):
        context = super(HomeView, self).get_context_data(**kwargs)
        #context['app_list'] = ['polls', 'books']
        dicVerbose = {}
        for app in apps.get_app_configs():
            if 'site-packages' not in app.path:
                dicVerbose[app.label] = app.verbose_name
        context['verbose_dict'] = dicVerbose
        return context

if 'site-package' not in app.path :

외부 라이브러의 물리적 디렉토리 구조는 'site-packages'를 포함하고 있으므로, 내가 추가로 구성한 앱만을 딕셔너리에 추가하기 위함이다.

 

- home.html

{% extends "base.html" %}

{% block content %}
    <h2>Django Applications</h2>
    <ul>
        {% for key, value in verbose_dict.items %}
            <li><a href="{% url key|add:':index' %}">{{ value }}</a></li>
        {% endfor %}
    </ul>
{% endblock content %}

 

'Django' 카테고리의 다른 글

17. 로그인, 로그아웃, 회원가입 기능 구현  (0) 2021.04.15
16. 게시판 페이징 기능 구현하기  (0) 2021.04.15
14. 폼 클래스  (0) 2021.04.08
13. 템플릿 상속  (0) 2021.04.08
12. Template 주석, HTML 이스케이프  (0) 2021.04.08

- polls/forms.py

from django import forms

class NameForm(forms.Form):
    your_name = forms.CharField(label='너의 이름은', max_length=100)

 

- polls/views.py

def get_name(request):
    # POST 방식이면, 데이터가 담긴 제출된 폼으로 간주합니다.
    if request.method == 'POST':
        # request에 담긴 데이터로, 클래스 폼을 생성합니다.
        form = NameForm(request.POST)
        # 폼에 담긴 데이터가 유효한지 체크합니다.
        if form.is_valid():
            # 폼 데이터가 유효하면, 데이터는 clean_data로 복사됩니다.
            new_name = form.cleaned_data['your_name']
            # 로직에 따라 추가적인 처리를 합니다.
            print(new_name)
            # 새로운 URL로 리다이렉션시킵니다.
            return HttpResponseRedirect(reverse('polls:index'))
    # POST 방식이 아니면(GET 요청임).
    # 빈 폼을 사용자에게 보여줍니다.
    else:
        form = NameForm()

    return render(request, 'polls/name.html', {'form': form})

 

- polls/urls.py

path('yourname/', views.get_name, name='yourname')

 

- polls/template/polls/name.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="{% url 'polls:yourname' %}" method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <input type="submit" value="제출">

</form>

</body>
</html>

 

- 결과 화면

 

출처: 한빛미디어, Django로 배우는 쉽고 빠른 웹 개발 파이썬 웹 프로그래밍

+ Recent posts