<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>ssu-uky.log</title>
        <link>https://velog.io/</link>
        <description>삽질과 저장소의 그 중간</description>
        <lastBuildDate>Mon, 15 Jan 2024 01:44:44 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. ssu-uky.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/ssu-uky" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[django] Q 객체란?]]></title>
            <link>https://velog.io/@ssu-uky/django-Q-%EA%B0%9D%EC%B2%B4%EB%9E%80</link>
            <guid>https://velog.io/@ssu-uky/django-Q-%EA%B0%9D%EC%B2%B4%EB%9E%80</guid>
            <pubDate>Mon, 15 Jan 2024 01:44:44 GMT</pubDate>
            <description><![CDATA[<h2 id="django-에서-q란">Django 에서 Q란?</h2>
<h3 id="장고의-orm에서-복잡한-데이터베이스-쿼리를-구성할-때-사용">장고의 ORM에서 복잡한 데이터베이스 쿼리를 구성할 때 사용.</h3>
<p>내가 사용했던 Q의 객체는 </p>
<pre><code class="language-py">class UserAuctionListView(APIView):
    permission_classes = [IsAuthenticated]
    # 경매 주최자 or 경매 낙찰자가 해당 유저인 경매 목록
    def get(self, request, user_pk):
        auction_rooms = AuctionRoom.objects.filter(Q(auction_host=user_pk) | Q(auction_winner=user_pk))
        serializer = AuctionRoomSerializer(auction_rooms, many=True)
        return Response(serializer.data,  status=status.HTTP_200_OK)</code></pre>
<p>이 부분 이였다.</p>
<p>Q 객체 쿼리를 사용한 이유는,
경매 주최자와 경매 낙찰자를 AuctionRoom 에서 한번에 필터링 하기 위해 사용했다.
다른 조건문을 사용해서 필터링을 이용할 수 있었지만,
Q라는 객체는 데이터베이스에서 여러 조건을 적용해서 OR , AND 연산자와 조합해서 사용하기에 유용하다고 해서 사용했다.</p>
<p>Q() 은 AuctionRoom.objects.all() 과 똑같다.
AuctionRoom 전체를 변수에 담아두고, q변수 안에 조건들을 넣어주는 느낌이라고 생각하면 된다.</p>
<hr>
<h3 id="f-객체">F 객체</h3>
<p>번외로 F 객체도 있다.
F객체는 데이터베이스 쿼리에서 필드간의 비교를 수행하기위해 사용된다.
예를들어 하나의 필드 값을 다른 필드 값과 비교하거나, 두 필드값을 결합하여 쿼리를 작성하는데 사용할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Django] migration 오류 날 경우 shell로 데이터 넣기]]></title>
            <link>https://velog.io/@ssu-uky/Django-migration-%EC%98%A4%EB%A5%98-%EB%82%A0-%EA%B2%BD%EC%9A%B0-shell%EB%A1%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%84%A3%EA%B8%B0</link>
            <guid>https://velog.io/@ssu-uky/Django-migration-%EC%98%A4%EB%A5%98-%EB%82%A0-%EA%B2%BD%EC%9A%B0-shell%EB%A1%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%84%A3%EA%B8%B0</guid>
            <pubDate>Mon, 11 Dec 2023 17:44:06 GMT</pubDate>
            <description><![CDATA[<p>장고에서 마이그레이션과 마이그레이트를 하면 일반적으로 데이터가 동기화가 되어야한다...</p>
<pre><code class="language-py">python manage.py makemigrations</code></pre>
<pre><code class="language-py">python manage.py migrate</code></pre>
<p>이렇게 해도 안 될 경우..</p>
<pre><code class="language-py">python manage.py makemigrations users</code></pre>
<pre><code class="language-py">python manage.py makemigrations tasks</code></pre>
<p>폴더별로 마이그레이션을 해주면 저번엔 되었었는데 이번엔 안된다..
다시 해도 안된다..</p>
<hr>
<p>앱 구조를 잘못짰나?..
그래서 일단 급한 마음에.. 쿼리로 들어가서 확인을 해보았다..</p>
<pre><code class="language-py">python manage.py shell</code></pre>
<pre><code class="language-py">&gt;&gt;&gt; from tasks.models import Task
&gt;&gt;&gt; from tasks.models import SubTask
&gt;&gt;&gt; from tasks.models import Team
&gt;&gt;&gt; from users.models import User
&gt;&gt;&gt; Team.objects.all()
&lt;QuerySet []&gt;
</code></pre>
<p>흠.. 왜 데이터에 아무것도 안들어가있을까..
Team 데이터만 안들어간다..</p>
<p>Team을 나눠서 그런걸까...
그래서 강제로 넣는 시도를 했다..</p>
<pre><code class="language-py">for team_name in User.TeamChoices.values:
...     Team.objects.get_or_create(name=team_name) -&gt; 여기서 탭하고 작성해야함</code></pre>
<p>그랬더니</p>
<pre><code class="language-py">(&lt;Team: Team1&gt;, True)
(&lt;Team: Team2&gt;, True)
(&lt;Team: Team3&gt;, True)
(&lt;Team: Team4&gt;, True)
(&lt;Team: Team5&gt;, True)
(&lt;Team: Team6&gt;, True)
(&lt;Team: Team7&gt;, True)</code></pre>
<br>
그리고 나서 다시 조회를 해보니까

<pre><code class="language-py">&gt;&gt;&gt; Team.objects.all()

&lt;QuerySet [&lt;Team: Team1&gt;, &lt;Team: Team2&gt;, &lt;Team: Team3&gt;, &lt;Team: Team4&gt;, &lt;Team: Team5&gt;, &lt;Team: Team6&gt;, &lt;Team: Team7&gt;]&gt;</code></pre>
<p>이번엔 들어갔다...</p>
<p>왜지?</p>
<hr>
<p>일단 내 앱은 users / tasks 로 나뉘어있다.</p>
<p>users 앱</p>
<pre><code class="language-py">class User(AbstractBaseUser, PermissionsMixin):
    class TeamChoices(models.TextChoices):
        Team1 = &quot;Team1&quot;, &quot;Team1&quot;
        Team2 = &quot;Team2&quot;, &quot;Team2&quot;
        Team3 = &quot;Team3&quot;, &quot;Team3&quot;
        Team4 = &quot;Team4&quot;, &quot;Team4&quot;
        Team5 = &quot;Team5&quot;, &quot;Team5&quot;
        Team6 = &quot;Team6&quot;, &quot;Team6&quot;
        Team7 = &quot;Team7&quot;, &quot;Team7&quot;

    username = models.CharField(max_length=50, unique=True)

    USERNAME_FIELD = &quot;username&quot;
    REQUIRED_FIELDS = []

    team = models.CharField(
        max_length=50,
        choices=TeamChoices.choices,
        default=TeamChoices.Team1,
    )

    objects = CustomUserManager()

    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    is_admin = models.BooleanField(default=False)
    date_joined = models.DateTimeField(auto_now_add=True)
    last_login = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.username</code></pre>
<p>tasks앱</p>
<pre><code class="language-py">from django.db import models

from users.models import User


class Team(models.Model):
    name = models.CharField(
        max_length=50,
        choices=User.TeamChoices.choices,
        unique=True,
    )

    def __str__(self):
        return self.name


class Task(models.Model):
    create_user = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name=&quot;create_user&quot;,
    )
    title = models.CharField(max_length=255)
    content = models.TextField()
    is_complete = models.BooleanField(default=False)
    completed_date = models.DateTimeField(null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    modified_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.title


class SubTask(models.Model):
    task = models.ForeignKey(
        Task,
        on_delete=models.CASCADE,
        related_name=&quot;subtasks&quot;,
    )
    team = models.ManyToManyField(
        Team,
        related_name=&quot;subtasks_teams&quot;,
        blank=True,
    )
    subtask_create_user = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name=&quot;subtask_create_user&quot;,
    )
    sub_title = models.CharField(max_length=255, blank=True, null=True)
    sub_content = models.TextField(blank=True, null=True)

    is_complete = models.BooleanField(default=False)
    completed_date = models.DateTimeField(null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    modified_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        team_names = &quot;, &quot;.join([team.name for team in self.team.all()])
        return f&quot;{self.task.title} - Teams: {team_names}&quot;</code></pre>
<p>모델의 구조를 잘못 짠거일까...
흐음... 이 부분에서 쿼리로 넣는다고 생각하기까지가 좀 오래 걸렸다...</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로젝트] 예산관리 시스템 모델 고민]]></title>
            <link>https://velog.io/@ssu-uky/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%98%88%EC%82%B0%EA%B4%80%EB%A6%AC-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EB%AA%A8%EB%8D%B8-%EA%B3%A0%EB%AF%BC</link>
            <guid>https://velog.io/@ssu-uky/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%98%88%EC%82%B0%EA%B4%80%EB%A6%AC-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EB%AA%A8%EB%8D%B8-%EA%B3%A0%EB%AF%BC</guid>
            <pubDate>Fri, 24 Nov 2023 14:21:04 GMT</pubDate>
            <description><![CDATA[<h3 id="📍-개요">📍 개요</h3>
<p>예산관리 시스템 서비스를 제작하고 있다.</p>
<p>앱은 <code>users</code> <code>plans</code> <code>payments</code> 로 나누고, 연결하려고 한다.</p>
<p>서비스 내용을 간단하게 말하자면,</p>
<pre><code>1. 유저는 한 달 수입과 저축액을 입력하면,
한달수입 = 저축액 + 지출금액 으로 셋팅이 된다. (지출금액은 자동으로 셋팅 됨)

2. 사용자는 지출 시 지출금액을 입력하면, 일일 지출금액에 저장이 된다.</code></pre><hr>
<h3 id="🤔-고민-되는-부분">🤔 고민 되는 부분</h3>
<p>a. 일일 지출금액을 저장하고, 이걸 plan에서 OnetoOne 으로 받는게 좋을까?
b. 일일 지출금액을 payments에서 daily_spending으로 ManytoMany로 받는게 좋을까?</p>
<hr>
<p><img src="https://velog.velcdn.com/images/ssu-uky/post/36c1dc2f-716b-4741-9287-5c923481b792/image.png" alt=""></p>
<p>a로 하면.. 연결이 되어서 관리가 더 편할 것 같은데...</p>
<p>지금은 사진처럼 b로 진행중이다.. 
b로 진행중인 이유는..daily_plan을 한 달에 맞춰서
당일마다 얼마를 쓰면 좋을지.. 짜줘야하기때문에.. manytomany로 받았는데..
오히려 월 별로 나눠서 OnetoOne으로 연결해서 나누는게 더 나을지..</p>
<p>일단 해 보고 결정해야겠다...</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Django] python-magic 설치 오류]]></title>
            <link>https://velog.io/@ssu-uky/Django-python-magic-%EC%84%A4%EC%B9%98-%EC%98%A4%EB%A5%98</link>
            <guid>https://velog.io/@ssu-uky/Django-python-magic-%EC%84%A4%EC%B9%98-%EC%98%A4%EB%A5%98</guid>
            <pubDate>Wed, 25 Oct 2023 13:31:46 GMT</pubDate>
            <description><![CDATA[<p>새로운 프로젝트를 하던 도중에 아래의 파일을 설치하는데 오류가 났다.</p>
<pre><code class="language-py">python-magic==0.4.27
python-magic-bin==0.4.14</code></pre>
<p>예전에도 윈도우 환경에서는 문제 없다가 mac환경에서만 문제 있던 일이 있어서 검색해 보았더니.. 역시나 맞았다..</p>
<blockquote>
<p>python-magic-bin 0.4.14는 OSX, w32 및 w64용 휠을 제공하지만 리눅스용 휠은 제공하지 않습니다.그리고 PyPI에는 소스코드가 없습니다.</p>
</blockquote>
<p>requirements.txt 에서 일단 주석처리 한 후,</p>
<pre><code class="language-py">pip install git+https://github.com/julian-r/python-magic.git</code></pre>
<p>이걸로 설치했더니 됐다...</p>
<p><a href="https://stackoverflow.com/questions/66732553/meeting-a-pip-requirement-using-an-alternative-module">참고 자료</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[django] migrations 가 안되는 이유?]]></title>
            <link>https://velog.io/@ssu-uky/django-migrations-%EA%B0%80-%EC%95%88%EB%90%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</link>
            <guid>https://velog.io/@ssu-uky/django-migrations-%EA%B0%80-%EC%95%88%EB%90%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</guid>
            <pubDate>Sun, 17 Sep 2023 13:08:44 GMT</pubDate>
            <description><![CDATA[<h2 id="📍-error">📍 ERROR</h2>
<h3 id="✏️-상황-설명">✏️ 상황 설명</h3>
<p>프로젝트를 하는 중에 pull을 받은 후에 migrations 을 하는 상황이였다.</p>
<blockquote>
<p><code>python manage.py makemigrations</code> 을 하면
<code>No changes detected</code> 가 나오는 상황...</p>
</blockquote>
<p>분명 변경되는 모델이 있는데.. 왜 migration이 안되는지 이해 불가..</p>
<p><img src="https://velog.velcdn.com/images/ssu-uky/post/df8faa77-d57c-4520-b850-3c9efc816817/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/ssu-uky/post/3773425e-9093-4bb0-8cda-72bb53ae0a8a/image.png" alt=""></p>
<p>암튼 그래서 migrate도 해보았는데
와중에 <code>python manage.py migrate</code> 는 평소처럼 되는 상황..</p>
<p><img src="https://velog.velcdn.com/images/ssu-uky/post/c6eb5bea-91be-43e0-a2b6-2cdc8c1992e0/image.png" alt=""></p>
<p><code>python manage.py makemigrations</code> 를 하면 할 게 없다고 나오는데...</p>
<p><code>python manage.py showmigrations</code> 로 확인을 하면
마이그레이션이 정작 안 되어 있는 상황을 발견할 수 있다...</p>
<p>아직 개발 초기단계라 db를 지워도 되는 상황이라 모든 데이터를 지우고 migrations 파일을 지우고 다시 해도 계속 똑같은 에러 발생...</p>
<p><img src="https://velog.velcdn.com/images/ssu-uky/post/3b0b399d-eb7f-4c12-a86c-221082a2edbb/image.png" alt=""></p>
<p>settings에도 앱이 모두 등록 되어 있는데...
왜? why? 안될까 ???</p>
<p>일단 예상 할 수 있는 부분..</p>
<blockquote>
<ol>
<li>db를 nosql(mongodb)에서 rdbms(일단 sqlite / 추후 변경 예정)로 변경해서 그런가? </li>
</ol>
</blockquote>
<p>-&gt; migrations 파일과 sqlite를 모두 지우고 다시 해봤지만?
-&gt; 안됨</p>
<blockquote>
<ol start="2">
<li>pull 을 잘못 받았나?</li>
</ol>
</blockquote>
<p>-&gt; git pull을 다시 받았는데도 안됨
-&gt; git clone 으로도 시도해보았지만? 역시나 안됨</p>
<hr>
<h2 id="💡-해결">💡 해결</h2>
<blockquote>
<p>python manage.py makemigrations <strong>app_name</strong></p>
</blockquote>
<p>app_name에다가 정말 app이름(폴더명)을 넣으면 된다.</p>
<blockquote>
<p>예를 들면
python manage.py makemigrations <strong>users</strong>
python manage.py makemigrations <strong>auctions</strong></p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/ssu-uky/post/5daa4a76-8f2e-448e-ad6e-c34f28e9704c/image.png" alt=""></p>
<p>그럼 분명 안되던게? 일일히 migration이 된다!!!</p>
<p>앱 별로 일일히 해주면 하나씩 강제로? migration이 되는 걸 볼 수 있다..</p>
<p>이 때 주의할 점은 ** migrate 하기 전에!!!**
무조건 모든 앱을 일일히 makemigrations 해준 후, migrate를 해주어야한다.</p>
<p>migrate를 먼저하면 의존성이 꼬이기때문에 또 머리가 아픈 이슈가 생긴다...</p>
<p>어떻게 알았냐구요?</p>
<p><del>저도 알고 싶지 않았어요... 다행히 db를 날려도 되는 상황이여서 머리가 반만 아팠습니다...</del></p>
<hr>
<p>그럼 지금처럼 데이터가 없으면 다 지우고 하면 되지만?
데이터가 있는 경우에는? ... </p>
<blockquote>
<p>python manage.py migrate --fake app_name zero
python manage.py migrate --fake <strong>users</strong> zero</p>
</blockquote>
<p>하면 된다고 한다..</p>
<p>암튼 해결 완료...!!!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[LeetCode] Valid Palindrome]]></title>
            <link>https://velog.io/@ssu-uky/%EC%9B%90%ED%8B%B0%EB%93%9C-%ED%94%84%EB%A6%AC%EC%98%A8%EB%B3%B4%EB%94%A9-Valid-Palindrome</link>
            <guid>https://velog.io/@ssu-uky/%EC%9B%90%ED%8B%B0%EB%93%9C-%ED%94%84%EB%A6%AC%EC%98%A8%EB%B3%B4%EB%94%A9-Valid-Palindrome</guid>
            <pubDate>Mon, 28 Aug 2023 11:55:27 GMT</pubDate>
            <description><![CDATA[<h2 id="📚-문제">📚 문제</h2>
<p><a href="https://leetcode.com/problems/valid-palindrome/">Valid Palindrome</a></p>
<blockquote>
<p>A phrase is a palindrome</p>
</blockquote>
<p>if, after converting all uppercase letters into lowercase letters</p>
<blockquote>
</blockquote>
<p>and removing all non-alphanumeric characters,</p>
<blockquote>
</blockquote>
<p>it reads the same forward and backward.</p>
<blockquote>
</blockquote>
<p>Alphanumeric characters include letters and numbers.</p>
<blockquote>
</blockquote>
<p>Given a string s, return true if it is a palindrome, or false otherwise.</p>
<h3 id="📍-예시">📍 예시</h3>
<pre><code class="language-py">** Example 1: **
Input: s = &quot;A man, a plan, a canal: Panama&quot;
Output: true
Explanation: &quot;amanaplanacanalpanama&quot; is a palindrome.

** Example 2: **
Input: s = &quot;race a car&quot;
Output: false
Explanation: &quot;raceacar&quot; is not a palindrome.

** Example 3: **
Input: s = &quot; &quot;
Output: true
Explanation: s is an empty string &quot;&quot; after removing non-alphanumeric characters.
Since an empty string reads the same forward and backward, it is a palindrome.</code></pre>
<h4 id="조건">조건</h4>
<ul>
<li>1 &lt;= s.length &lt;= 2 * 105</li>
<li>s consists only of printable ASCII characters.</li>
</ul>
<hr>
<h2 id="✏️-문제-해석">✏️ 문제 해석</h2>
<ul>
<li>palindrome : 회문 == 앞으로 읽어도 거꾸로 읽어도 똑같은 문장
ex) level, 토마토</li>
</ul>
<blockquote>
</blockquote>
<p>주어진 문장에 대문자가 있다면 모두 소문자로 변경하고,</p>
<blockquote>
</blockquote>
<p>알파벳과 숫자가 아닌 모든 것은 제거한다 (띄어쓰기, 따옴표 등 모두 제거)</p>
<blockquote>
</blockquote>
<p>앞에서 읽었을 때와 거꾸로 읽었을 때 똑같이 읽혀야한다.</p>
<blockquote>
</blockquote>
<p>이 문장은 영문자와 숫자만을 포함한다.</p>
<blockquote>
</blockquote>
<p>이 문자가 회문이면 true를 반환하고, 회문이 아니라면 false를 반환한다.</p>
<hr>
<h3 id="💡-내가-생각한-풀이">💡 내가 생각한 풀이</h3>
<pre><code class="language-py">1. 주어진 문장 s를 lower를 사용하여 모두 소문자로 변경한다.
2. 알파벳과 숫자가 아닌 모든 항목은 제거한다. -&gt; ** alnum 사용 **
3. 제대로 읽었을 경우, 거꾸로 읽었을 경우를 비교해서 &quot;true&quot; or &quot;false&quot;를 출력한다. -&gt; [::-1] 사용</code></pre>
<pre><code class="language-py"># 빈 저장소 생성
temp = &quot;&quot;

# 소문자로 변경한 문자 저장
lower_text = s.lower()

# 소문자로 변경 후에 isalnum으로 문자/숫자가 아닌 모든 항목 제거 후, temp로 저장
for s_text in lower_text:
    if s_text.isalnum():
        temp += s_text
# print(temp)
# -&gt; amanaplanacanalpanama

# temp와 temp[::-1] 를 비교
if temp == temp[::-1]:
    print(f&quot;true&quot;)
else:
    print(f&quot;false&quot;)</code></pre>
<hr>
<h3 id="💡-leetcode-에-작성한-코드">💡 leetcode 에 작성한 코드</h3>
<pre><code class="language-py">class Solution:
    def isPalindrome(self, s: str) -&gt; bool:

        temp = &quot;&quot;

        s_text = s.lower()

        for s in s_text:
            if s.isalnum():
                temp += s
        print(temp)

        if temp == temp[::-1]:
            print(f&quot;true&quot;)
        else:
            print(f&quot;false&quot;)
</code></pre>
<h3 id="🪄-새로-알게-된---isalnum">🪄 새로 알게 된 - isalnum</h3>
<blockquote>
<p>문자열에서 특정 타입만 뽑아내는 방법</p>
<ol>
<li><p>숫자만 뽑아내기
isdigit()</p>
</li>
<li><p>문자만 뽑아내기
isalpha()</p>
</li>
<li><p>문자 &amp; 숫자만 뽑아내기
isalnum()</p>
</li>
</ol>
</blockquote>
<hr>
<p>leetcode
<img src="https://velog.velcdn.com/images/ssu-uky/post/3d7c6058-32f5-4a67-a832-4d68cad686fb/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/ssu-uky/post/eb20715d-ba6e-427c-b120-352cbb76ed69/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/ssu-uky/post/07acac51-4e78-4b77-871a-b8a9179dec04/image.png" alt=""></p>
<p>아니 대체 왜지?
print 로는 제대로 찍히는데 leetcode에서는 이번에도 output으로 다르게 찍힌다..
모두 false가 뜨는데... 음... </p>
<pre><code class="language-py">def isPalindrome(self, s: str) -&gt; bool:</code></pre>
<p>이 부분 때문에 안되는 것 같긴 한데...</p>
<hr>
<h2 id="📚-검색하다가-우연히-알게-된-답-">📚 검색하다가 우연히 알게 된 답 ...</h2>
<p><a href="https://velog.io/@ssu-uky/%EC%9B%90%ED%8B%B0%EB%93%9C-%ED%94%84%EB%A6%AC%EC%98%A8%EB%B3%B4%EB%94%A9-Merge-Sorted-Array">이 글</a> 에서 참고한 것 처럼 리스트컴프리헨션을 사용함</p>
<pre><code class="language-py">class Solution:
    def isPalindrome(self, s: str) -&gt; bool:
        strs = [char.lower() for char in s if char.isalnum()] 
        return strs == strs[::-1] </code></pre>
<p><img src="https://velog.velcdn.com/images/ssu-uky/post/ae4adfe6-fcb5-4d00-945f-fed00beffd92/image.png" alt=""></p>
<hr>
<p>...?</p>
<p>위에서 언급한 대로</p>
<pre><code class="language-py">def isPalindrome(self, s: str) -&gt; bool:</code></pre>
<p>이 부분을 생각 못한건 맞다...</p>
<p><strong>리스트 컴프리헨션</strong>에 대해서 더 자세히 공부해야겠다..
그리고 주어진 함수를 제대로 읽는 능력을 더 길러야겠다...</p>
<p>시간도 이리 적게 걸리다니?</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[LeetCode] Merge Sorted Array]]></title>
            <link>https://velog.io/@ssu-uky/%EC%9B%90%ED%8B%B0%EB%93%9C-%ED%94%84%EB%A6%AC%EC%98%A8%EB%B3%B4%EB%94%A9-Merge-Sorted-Array</link>
            <guid>https://velog.io/@ssu-uky/%EC%9B%90%ED%8B%B0%EB%93%9C-%ED%94%84%EB%A6%AC%EC%98%A8%EB%B3%B4%EB%94%A9-Merge-Sorted-Array</guid>
            <pubDate>Thu, 24 Aug 2023 13:02:02 GMT</pubDate>
            <description><![CDATA[<h2 id="📚-문제">📚 문제</h2>
<p><a href="https://leetcode.com/problems/merge-sorted-array/">Merge Sorted Array</a></p>
<blockquote>
<p>You are given two integer arrays nums1 and nums2, sorted in non-decreasing order,</p>
</blockquote>
<p>and two integers m and n, representing the number of elements in nums1 and nums2 respectively.</p>
<blockquote>
</blockquote>
<p>Merge nums1 and nums2 into a single array sorted in non-decreasing order.</p>
<blockquote>
</blockquote>
<p>The final sorted array should not be returned by the function,</p>
<blockquote>
</blockquote>
<p>but instead be stored inside the array nums1.</p>
<blockquote>
</blockquote>
<p>To accommodate this, nums1 has a length of m + n,</p>
<blockquote>
</blockquote>
<p>where the first m elements denote the elements that should be merged,</p>
<blockquote>
</blockquote>
<p>and the last n elements are set to 0 and should be ignored.</p>
<blockquote>
</blockquote>
<p>nums2 has a length of n.</p>
<h3 id="📍-예시">📍 예시</h3>
<pre><code class="language-py">** Example 1: **
Input: nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
Output: [1,2,2,3,5,6]
Explanation: The arrays we are merging are [1,2,3] and [2,5,6].
The result of the merge is [1,2,2,3,5,6] with the underlined elements coming from nums1.

** Example 2: **
Input: nums1 = [1], m = 1, nums2 = [], n = 0
Output: [1]
Explanation: The arrays we are merging are [1] and [].
The result of the merge is [1].

** Example 3 **
Input: nums1 = [0], m = 0, nums2 = [1], n = 1
Output: [1]
Explanation: The arrays we are merging are [] and [1].
The result of the merge is [1].
Note that because m = 0, there are no elements in nums1. The 0 is only there to ensure the merge result can fit in nums1.</code></pre>
<p>첫 느낌 .. 일단 처음 보는 영어문제라서 당황했다 ...
바로 해석 시작..</p>
<hr>
<h3 id="✏️-문제-해석">✏️ 문제 해석</h3>
<blockquote>
<p>오름차순으로 정렬 된 정수 배열 nums1, nums2 가 있다.
정수 m, n이 주어지눈데, 각각 nums1, nums2의 요소의 갯수이다.
<strong>-&gt; 주어진 요소의 갯수가 아니라 반환해야하는 요소의 갯수인듯...</strong></p>
</blockquote>
<p>두 배열을 하나의 배열로 합쳐라. 오름차순 정렬 필요. <strong>+ 자르지 않고 합치기</strong></p>
<blockquote>
</blockquote>
<p>마지막 정렬된 배열은 함수로 반환되지 않고, nums1에 포함되어 정렬되서 반환되어야한다.</p>
<blockquote>
</blockquote>
<p>nums1은 m + n의 길이를 가지며,
여기서 처음 m개의 요소는 병합해야 할 요소를 나타내고,</p>
<blockquote>
</blockquote>
<p>마지막 n개의 요소는 0으로 설정되어 무시한다.
nums2는 n의 길이를 가집니다.</p>
<hr>
<h3 id="💡-내가-생각한-풀이---1">💡 내가 생각한 풀이 - 1</h3>
<pre><code class="language-py">1. nums1을 m개의 갯수만큼 그대로 유지하고, 그 뒤에는 0으로 변경
2. nums2 를 n개의 갯수만큼 그대로 유지하고, 그 뒤에는 0으로 변경
3. nums1 을 [:m]으로 m개만 꺼내서 nums1로, nums2를 [:n]개만 꺼내서 다시 저장
4. 배열들을 합쳐서 nums1로 저장: nums1 = nums1 + nums2
5. 합친 배열 num1을 [:m+n]까지 자르기
6. 마지막 nums1 를 sort로 오름차순 정렬</code></pre>
<pre><code class="language-py">for i in range(m, len(nums1)):
    nums1[i] = 0
print(&quot;1 :&quot;, nums1)

for j in range(n, len(nums2)):
    nums2[i] = 0
print(&quot;2 :&quot;, nums2)

nums1 = nums1[:m]
nums2 = nums2[:n]
print(&quot;3 :&quot;, nums1, nums2)

nums1 = nums1+nums2
print(&quot;4 :&quot;, nums1)

nums1 = nums1[:m+n]
print(&quot;5 :&quot;, nums1)

nums1.sort()
print(&quot;6 :&quot;, nums1)</code></pre>
<hr>
<p>vscode
<img src="https://velog.velcdn.com/images/ssu-uky/post/2377f0b3-a880-402b-9ff5-06eb00447e97/image.png" alt=""></p>
<p>leetcode
<img src="https://velog.velcdn.com/images/ssu-uky/post/1dda9e92-ae81-4870-bc8f-52253ffb83eb/image.png" alt=""></p>
<p>다 잘 나오는데...
왜 .. 실패가 뜨는거지...
<img src="https://velog.velcdn.com/images/ssu-uky/post/1f3e3e1d-dcea-4c8f-b2df-47edf2ed0f34/image.png" alt=""></p>
<hr>
<h3 id="💡-내가-생각한-풀이---2">💡 내가 생각한 풀이 - 2</h3>
<pre><code class="language-py">1. nums1에서 0이 있다면 0을 제거하기
2. nums2에서 0이 있다면 0을 제거하기
3. nums1을 nums1+nums2로 재선언
4. nums1 을 m+n까지 자르기
5. nums1을 자른 후에 오름차순으로 정렬</code></pre>
<pre><code class="language-py">nums1 = [num for num in nums1 if num != 0]
print(&quot;1 :&quot; , nums1)

nums2 = [num2 for num2 in nums2 if num2 != 0]
print(&quot;2 :&quot;, nums2)

nums1 = nums1+nums2
print(&quot;3 :&quot;, nums1)

nums1 = nums1[:m+n]
print(&quot;4 :&quot;, nums1)

nums1.sort()
print(&quot;5 :&quot;, nums1)</code></pre>
<p>vscode
<img src="https://velog.velcdn.com/images/ssu-uky/post/284c3cfb-5a30-4da9-bfd5-62378ce4a2ef/image.png" alt=""></p>
<p>leetcode
<img src="https://velog.velcdn.com/images/ssu-uky/post/45b423e3-4aa0-4d35-970f-43beec8fd952/image.png" alt=""></p>
<p>하지만 결과는.. 여전히...
<img src="https://velog.velcdn.com/images/ssu-uky/post/f73559d6-1646-420a-a69a-25a1f840851f/image.png" alt=""></p>
<hr>
<h3 id="💡-도움을-받은-풀이">💡 도움을 받은 풀이</h3>
<pre><code class="language-py">1. nums1을 m까지 자른다.
2. nums2를 n까지 자른다.
3. nums1을 nums1+nums2를 합친 배열로 다시 저장한다.
4. nums1을 오름차순으로 정렬한다.</code></pre>
<pre><code class="language-py">nums1 = nums1[0:m]
print(&quot;1 :&quot;, nums1)

nums2 = nums2[0:n]
print(&quot;2 :&quot;, nums2)

nums1 = nums1+nums2
print(&quot;3 :&quot;, nums1)

nums1.sort()
print(&quot;4 :&quot;, nums1)</code></pre>
<p>vscode</p>
<p><img src="https://velog.velcdn.com/images/ssu-uky/post/163cc91a-8218-4c29-a3fd-c27e3be769d5/image.png" alt=""></p>
<p>leetcode
<img src="https://velog.velcdn.com/images/ssu-uky/post/65a47a0e-9a8e-402e-b114-ee5159d3a1dc/image.png" alt=""></p>
<p>결과..
<img src="https://velog.velcdn.com/images/ssu-uky/post/308d1e52-ddd9-43d2-bedf-988451b115b7/image.png" alt=""></p>
<p>세 개 다 case2 만 성공하고 1,3은 계속 실패한다...</p>
<p><del>여러개 검색해 본 결과..
nums1를 재선언하면 안된다고 하는데.. 음.. 음 ... 나는 왜 재선언을 제거해도 똑같지... 일단 ... 좀 더 생각해보기...</del></p>
<h3 id="💡-드디어-찾은-답">💡 드디어 찾은 답</h3>
<pre><code class="language-py">class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -&gt; None:
        &quot;&quot;&quot;
        Do not return anything, modify nums1 in-place instead.
        &quot;&quot;&quot;

        # nums1[:] -&gt; 재선언으로 안받아들임

        del(nums1[m:])
        nums1[0:m] += nums2[0:n]
        nums1.sort()</code></pre>
<p>내 코드보다 ... 많이 줄었는데 !
이렇게 답이 나오다니..
<img src="https://velog.velcdn.com/images/ssu-uky/post/6cf951d9-4072-43d4-ae0e-6a9d2ae69dcc/image.png" alt=""></p>
<blockquote>
<h4 id="🪄-리스트-컴프리헨션list-comprension">🪄 리스트 컴프리헨션(List Comprension)</h4>
<p>리스트 컴프리헨션이란 리스트를 직관적으로 볼 수 있도록 생성하는 방법
대괄호로 감싸고 내부에 for문과 if문을 사용하여 반복하며 조건에만 만족하는 것을 리스트로 생성
리스트 컴프리헨션을 사용하는 이유는 <strong>직관적으로 확인가능, 속도가 빠름</strong></p>
</blockquote>
<p><del>&gt; 도움 주실 분.. 환영합니다...</del></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[GCP] ssh 원격접속 timeout ..]]></title>
            <link>https://velog.io/@ssu-uky/GCP-ssh-%EC%9B%90%EA%B2%A9%EC%A0%91%EC%86%8D-timeout-</link>
            <guid>https://velog.io/@ssu-uky/GCP-ssh-%EC%9B%90%EA%B2%A9%EC%A0%91%EC%86%8D-timeout-</guid>
            <pubDate>Sun, 13 Aug 2023 14:52:59 GMT</pubDate>
            <description><![CDATA[<h3 id="문제">문제</h3>
<p>GCP를 처음 이용해보는 와중에 처음 접속은 잘 되다가 중간에 잠시만 멈췄다가 다시 시작하면 계속 뜨는 timeout...
<img src="https://velog.velcdn.com/images/ssu-uky/post/561880a2-3307-4d79-9dd9-187b9201e1d2/image.png" alt=""><img src="https://velog.velcdn.com/images/ssu-uky/post/7e797722-0b77-412e-91eb-ab7c9a3697ed/image.png" alt=""><img src="https://velog.velcdn.com/images/ssu-uky/post/48ceca29-904f-43ef-9005-5299358603d9/image.png" alt=""></p>
<p>aws 사용했을 때도 뜬 적이 있어서 접속시간도 늘려보고 시도횟수도 늘려봤는데 여전히 timeout...</p>
<p><code>darwin arm64</code> 라고 떠있어서 맥북의 문제인가.. 하고 계속 헤매다가..</p>
<p>ping으로 터미널에서 실행해보았는데 이건 또 잘 들어가진다고 나오고...</p>
<blockquote>
</blockquote>
<p><code>ping IP주소</code>
<code>ping 123.123.123</code> -&gt; 이런 식으로 하면 접속 가능 여부 확인 가능</p>
<p><img src="https://velog.velcdn.com/images/ssu-uky/post/c04cc880-d6da-4743-8e1e-85856064cbd6/image.png" alt=""></p>
<p>메모리 부족인가? 싶어서 메모리 확인도 해봤는데 메모리는 부족하진 않고...
<img src="https://velog.velcdn.com/images/ssu-uky/post/f0c305ce-b8c9-4147-8ea3-740134b634fb/image.png" alt=""></p>
<p>방화벽도 다시 확인해보았는데? 다 열려있었고...
<img src="https://velog.velcdn.com/images/ssu-uky/post/0c35cb36-5585-4d50-a4b0-e1991d70c5ba/image.png" alt=""></p>
<hr>
<h3 id="해결">해결</h3>
<p>진짜 멘붕 오는 와중에 한 줄기의 빛...
<img src="https://velog.velcdn.com/images/ssu-uky/post/8aca2e85-bec5-4a24-8e53-c41bdb5ccc5e/image.png" alt=""></p>
<p>VM 인스턴스에서 실행하고 있는 인스턴스에 들어가서 수정을 누르면
하단에 커스텀 메타데이터라는 공간이 있다..</p>
<blockquote>
<p>sudo ufw allow 22</p>
</blockquote>
<p>라고 추가시켜주고 다시 ssh 접속을 실행해보니... 드디어 해결 (눈물광광)
이틀동안 삽질했는데 ㅠㅠ 드디어 언제나 접속이 가능하다ㅠㅠㅠㅠ</p>
<hr>
<p>도와주신.. 조교친구와 출처분께 감사를... (꾸벅)
출처 : <a href="https://mjs1995.tistory.com/253">https://mjs1995.tistory.com/253</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[컨볼루션 (CONVOLUTION) 이란?]]></title>
            <link>https://velog.io/@ssu-uky/%EC%BB%A8%EB%B3%BC%EB%A3%A8%EC%85%98-CONVOLUTION-%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@ssu-uky/%EC%BB%A8%EB%B3%BC%EB%A3%A8%EC%85%98-CONVOLUTION-%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Fri, 28 Jul 2023 20:12:50 GMT</pubDate>
            <description><![CDATA[<h2 id="컨볼루션-convolution">컨볼루션 (CONVOLUTION)</h2>
<ul>
<li>모델 트레이닝 (Model Training)의 일종</li>
<li>일종의 커널행렬을 사용하여 이미지를 스캔하고 제공하며 특정 효과를 얻기위해 필터를 적용함</li>
</ul>
<p><img src="https://velog.velcdn.com/images/ssu-uky/post/55c5f2c8-6bec-4307-8a39-eb93c940fd23/image.png" alt=""></p>
<p>이미지를 기준으로 특징 탐지기가 루프를 돈다.</p>
<hr>
<h3 id="컨볼루션-신경망">컨볼루션 신경망</h3>
<p>이미지를 다룰 때에는 픽셀간의 공간 의존성을 보존</p>
<ol>
<li>특징 감지기를 이미지에 실행</li>
<li>특징 탐지기로 컨볼루션 과정 실행 <strong>(행렬을 곱함)</strong></li>
<li>특징 탐지기 생성 후 사용  <strong>(특징 맵)</strong></li>
<li>풀링을 수행해 풀링 특성들의 부분집합 생성</li>
<li>부분집합들을 평탄화 시켜 신경망에 공급</li>
</ol>
<hr>
<h4 id="첫번째-루프">&lt;첫번째 루프&gt;</h4>
<p><img src="https://velog.velcdn.com/images/ssu-uky/post/b402e00c-e44d-4e2e-840f-42ad8d9d88df/image.png" alt=""></p>
<h4 id="두번째-루프">&lt;두번째 루프&gt;</h4>
<p><img src="https://velog.velcdn.com/images/ssu-uky/post/d94cb7cc-3344-466f-965e-0eae3cec0331/image.png" alt=""></p>
<h4 id="세번째-루프">&lt;세번째 루프&gt;</h4>
<p><img src="https://velog.velcdn.com/images/ssu-uky/post/b873bf83-792c-4982-9d25-90efdac5742e/image.png" alt=""></p>
<h4 id="네번째-루프">&lt;네번째 루프&gt;</h4>
<p><img src="https://velog.velcdn.com/images/ssu-uky/post/fa10c927-4cc9-4107-8554-152de84de82b/image.png" alt=""></p>
<p>사진 기준 3x3 행렬은 9번의 루프를 돌면 마지막 특징맵이 완성 된다.</p>
<p>완성 된 특징맵은 필터가 적용 된 이미지로 만들어져서 보여진다 !!</p>
<blockquote>
<p>출처 : 유데미 <a href="https://kmooc.udemy.com/course/best-machine-learning-6">[Machine Learning 완벽 실습 : 6가지 실제 사례 직접 해결하기]</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[ubuntu] 우분투 파일 변경 시 gunicorn ngnix 재 실행 명령어]]></title>
            <link>https://velog.io/@ssu-uky/ubuntu-%EC%9A%B0%EB%B6%84%ED%88%AC-%ED%8C%8C%EC%9D%BC-%EB%B3%80%EA%B2%BD-%EC%8B%9C-gunicorn-ngnix-%EC%9E%AC-%EC%8B%A4%ED%96%89-%EB%AA%85%EB%A0%B9%EC%96%B4</link>
            <guid>https://velog.io/@ssu-uky/ubuntu-%EC%9A%B0%EB%B6%84%ED%88%AC-%ED%8C%8C%EC%9D%BC-%EB%B3%80%EA%B2%BD-%EC%8B%9C-gunicorn-ngnix-%EC%9E%AC-%EC%8B%A4%ED%96%89-%EB%AA%85%EB%A0%B9%EC%96%B4</guid>
            <pubDate>Tue, 18 Jul 2023 21:07:53 GMT</pubDate>
            <description><![CDATA[<h3 id="우분투-사용-시-파일이-변경되면-gunicorn-과-nginx를-재실행-해주어야한다">우분투 사용 시 파일이 변경되면 gunicorn 과 nginx를 재실행 해주어야한다.</h3>
<h4 id="gunicorn-재실행">gunicorn 재실행</h4>
<pre><code>pkill gunicorn</code></pre><pre><code>sudo systemctl restart gunicorn</code></pre><pre><code>nohup gunicorn --daemon config.wsgi &amp;</code></pre><pre><code>nohup gunicorn --daemon &lt;폴더이름 or 서버이름&gt;.wsgi &amp;</code></pre><p>나는 장고를 주로 사용해서 포트번호가 0.0.0.0:8000 인거임</p>
<pre><code>gunicorn config.wsgi:application --bind 0.0.0.0:8000 --daemon &amp;</code></pre><h4 id="nginx-재실행">nginx 재실행</h4>
<pre><code>sudo service nginx restart</code></pre><pre><code>sudo service nginx reload</code></pre><pre><code>sudo nginx -t</code></pre><p>ngnix 문법 검사까지 완료하기~!</p>
<blockquote>
</blockquote>
<p>nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful</p>
<p>ngnix 가 문제없다고 뜬 다면 성공 !</p>
<p>가끔 이렇게 문법오류는 없는데도 오류가 날 때가 있다.
그럴 땐 <strong>nginx 폴더 안에 conf 파일</strong>을 살펴보기 !
<strong>ngnix/available/ 안에 파일을 살펴봐야 할 수도 있음!</strong></p>
<p>상황에 따라 맞게 설정해주면 됨 ~!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로젝트] 네가 꾸민 케이크 회고]]></title>
            <link>https://velog.io/@ssu-uky/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%84%A4%EA%B0%80-%EA%BE%B8%EB%AF%BC-%EC%BC%80%EC%9D%B4%ED%81%AC-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@ssu-uky/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%84%A4%EA%B0%80-%EA%BE%B8%EB%AF%BC-%EC%BC%80%EC%9D%B4%ED%81%AC-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Tue, 18 Jul 2023 16:09:47 GMT</pubDate>
            <description><![CDATA[<h2 id="🎂-프로젝트-소개">🎂 프로젝트 소개</h2>
<p>크리스마스 시즌마다 유행하던 <a href="https://colormytree.me/">내 트리를 꾸며줘 </a>를 모티브로 생일인 사람에게 케이크를 주면서 생일축하해주는 롤링페이퍼 서비스 입니다.</p>
<p><strong>현재 서버 닫힘</strong>
<strong>리팩토링 중 (commit history, testcode 추가예정)</strong></p>
<blockquote>
</blockquote>
<p>[배포 사이트]
<a href="https://www.naekkukae.store/">https://www.naekkukae.store/</a>
[프론트 깃허브 주소]
<a href="https://github.com/ssu-uky/cake-front.git">https://github.com/ssu-uky/cake-front.git</a>
[백엔드 깃허브 주소]
<a href="https://github.com/ssu-uky/cake-server.git">https://github.com/ssu-uky/cake-server.git</a>
[API 문서]
<a href="https://birthday-cake.gitbook.io/naekkukae/">https://birthday-cake.gitbook.io/naekkukae/</a></p>
<hr>
<h2 id="🛠️-개발-시작">🛠️ 개발 시작</h2>
<blockquote>
</blockquote>
<p>기간 : 3주
프론트엔드 1명, 백엔드 1명으로 진행
대면으로 개발 진행</p>
<h3 id="핵심-기능">핵심 기능</h3>
<blockquote>
</blockquote>
<ul>
<li>Simple JWT 사용으로 로그인 보안 강화</li>
<li>로그인 시 보안을 위해 토큰을 local Storage 와 Session Storage 에 따로 분리</li>
<li>이메일 가입 시 이메일 인증 필수</li>
<li>카카오톡 소셜로그인 구현</li>
<li>가입 한 type 구별</li>
<li>본인의 편지만 오픈 가능</li>
<li>비밀번호 변경 및 분실 시 이메일로 받은 인증 링크에서만 변경 가능
(카카오톡으로 가입했을 경우, 카카오톡에 연동되어있는 이메일로 인증 요청 이메일이 보내집니다.)</li>
<li>피드백 요청 기능</li>
<li>비속어 작성 차단 기능</li>
</ul>
<hr>
<h3 id="서비스-과정">서비스 과정</h3>
<blockquote>
</blockquote>
<ol>
<li>사용자는 로그인을 한 후에 본인의 테이블을 원하는 색으로 만듭니다.</li>
<li>테이블은 만든 사람에게는 고유의 주소가 주어집니다.</li>
<li>그 주소를 복사하여, 다른 사람들에게 주면 로그인을 하지 않은 사람들도 케이크를 고른 후, 편지를 쓸 수 있습니다.</li>
<li>편지를 쓰면, 받은 편지(케이크)의 갯수와 방문자가 고른 케이크가 사용자의 테이블에 올려집니다.
4-1. 비속어가 들어 있을 경우, 편지는 post 되지 않습니다.</li>
<li>받은 편지는 사용자만 읽을 수 있습니다.</li>
</ol>
<ul>
<li>추가적으로 넣고 싶은 기능<ul>
<li><del>사용자의 피드백 받기</del> (완료)</li>
<li>사용자의 생일을 입력받고 <strong>생일 당일</strong> 에 편지를 읽을 수 있게 하기
(이런 서비스는 한 순간에 반짝 서비스로 .. 사용자가 1년동안 기다리다가 서비스 자체를 까먹을 것 같아서 일단 보류함)</li>
<li>본인의 테이블에 편지가 업데이트 되면 카톡으로 알림 or 이메일로 알림 기능 넣기</li>
</ul>
</li>
</ul>
<hr>
<h3 id="아키텍처architecture">아키텍처(Architecture)</h3>
<p><img src="https://velog.velcdn.com/images/ssu-uky/post/a6d4ca70-8486-4e8a-b345-03923bff4882/image.png" alt=""></p>
<hr>
<h3 id="💥-issue">💥 ISSUE</h3>
<ul>
<li>소셜로그인을 도입하는 와중에 카카오 로그인을 백엔드에서 구현했는데 이 부분에서 3일은 헤맨 것 같다..<pre><code class="language-py">class KakaoSignView(APIView):
  def get(self, request):
      client_id = KAKAO_REST_API_KEY
      redirect_uri = &quot;https://manage.naekkukae.store/auth/kakao/callback&quot;
      return redirect(
          f&quot;https://kauth.kakao.com/oauth/authorize?client_id={client_id}&amp;redirect_uri={redirect_uri}&amp;response_type=code&quot;
      )

</code></pre>
</li>
</ul>
<p>class KakaoCallbackView(APIView):
    def get(self, request):
        try:
            code = request.GET.get(&quot;code&quot;)
            client_id = KAKAO_REST_API_KEY
            redirect_uri = &quot;<a href="https://manage.naekkukae.store/auth/kakao/callback&quot;">https://manage.naekkukae.store/auth/kakao/callback&quot;</a>
            token_request = requests.post(
                &quot;<a href="https://kauth.kakao.com/oauth/token&quot;">https://kauth.kakao.com/oauth/token&quot;</a>,
                data={
                    &quot;grant_type&quot;: &quot;authorization_code&quot;,
                    &quot;client_id&quot;: client_id,
                    &quot;redirect_uri&quot;: redirect_uri,
                    &quot;code&quot;: code,
                },
            )
            token_json = token_request.json()</p>
<pre><code>        error = token_json.get(&quot;error&quot;, None)

        if error is not None:
            return Response({&quot;message&quot;: &quot;INVALD_CODE&quot;}, status=HTTP_400_BAD_REQUEST)

        access_token = token_json.get(&quot;access_token&quot;)
        refresh_token = token_json.get(&quot;refresh_token&quot;)

        profile_request = requests.get(
            &quot;https://kapi.kakao.com/v2/user/me&quot;,
            headers={&quot;Authorization&quot;: f&quot;Bearer {access_token}&quot;},
        )

        profile_json = profile_request.json()
        kakao_account = profile_json.get(&quot;kakao_account&quot;)
        email = kakao_account.get(&quot;email&quot;, None)
        nickname = kakao_account.get(&quot;profile&quot;).get(&quot;nickname&quot;, None)

    except KeyError:
        return Response({&quot;message&quot;: &quot;INVALID_TOKEN&quot;}, status=HTTP_400_BAD_REQUEST)

    if User.objects.filter(email=email).exists():
        kakao_user = User.objects.get(email=email)
        tokens = RefreshToken.for_user(kakao_user)
        response = HttpResponseRedirect(
            f&quot;https://naekkukae.store/KakaoLogin?refresh={str(tokens)}&amp;access={str(tokens.access_token)}&amp;user_pk={kakao_user.pk}&quot;
        )
        return response

    else:
        if email:
            user = User.objects.create(
                email=email,
                name=nickname,
                social_type=&quot;kakao&quot;,
                is_active=True,  # 카카오로 회원가입 한 유저는 이메일 인증 필요없음 (항상 is_active=True로 설정)
            )

            tokens = RefreshToken.for_user(user)
            response = HttpResponseRedirect(
                f&quot;https://naekkukae.store/KakaoLogin?refresh={str(refresh_token)}&amp;access={str(tokens.access_token)}&amp;user_pk={user.pk}&quot;
            )
            # return Response(response, id, status=HTTP_200_OK)
            return response
        else:
            return Response(
                {&quot;message&quot;: &quot;카카오 아이디 혹은 카카오 이메일이 없습니다.&quot;},
                status=HTTP_400_BAD_REQUEST,
            )</code></pre><pre><code>

### 느낀 점
이번 프로젝트로 넥스트를 처음으로 접해보았는데 넥스트 완전 사기캐인 것 같다..
그래도 프론트를 직접 개발해보니 서버와의 이해도가 훨씬 높아졌다.

개발하다가 시간이 부족하고 더 넣고 싶은 기능이 많아서 프로젝트가 끝난 후에도 혼자서 손을 봤지만, 하다보니 계속 추가하고 싶은 기능이 생기고 있다.

시간이 나면 추가하고 싶은 기능들을 정리하고, 추가해서 개발해보아야겠다.</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[프로젝트] 특허의 신 프로젝트 회고]]></title>
            <link>https://velog.io/@ssu-uky/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%8A%B9%ED%97%88%EC%9D%98-%EC%8B%A0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@ssu-uky/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%8A%B9%ED%97%88%EC%9D%98-%EC%8B%A0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Mon, 17 Jul 2023 06:38:42 GMT</pubDate>
            <description><![CDATA[<h2 id="💡-프로젝트-소개">💡 프로젝트 소개</h2>
<p>특허를 내는 시간도 단축하고, 특허를 편리하게 낼 수 있도록 도와주는 서비스</p>
<ul>
<li><p>특허를 내기 전, 특허 가능성을 검토해주어 자신의 아이디어가 특허권을 얻을 수 있는지 알아볼 수 있도록 특허가능성검토 를 해주는 시스템입니다.</p>
</li>
<li><p>발명의 명칭 이라는 단계에서 유저들이 많이 포기한다는 이야기를 듣고, 키워드입력방식을 이용하여 특허청과 연동시켜 실시간으로 자신이 생각하는 발명과 관련 된 아이디어의 현황을 보여줍니다.</p>
</li>
</ul>
<blockquote>
</blockquote>
<p>[배포 사이트]
<a href="https://growbeyond.store/">https://growbeyond.store/</a>
[프론트 깃허브 주소]
<a href="https://github.com/ssu-uky/2-GROWBEYOND-Front-End.git">https://github.com/ssu-uky/2-GROWBEYOND-Front-End.git</a>
[백엔드 깃허브 주소]
<a href="https://github.com/ssu-uky/patent-upload.git">https://github.com/ssu-uky/patent-upload.git</a>
[API 문서]
<a href="https://ssu-uky.gitbook.io/grow-patent/">https://ssu-uky.gitbook.io/grow-patent/</a></p>
<hr>
<h2 id="🛠️-시작-과정">🛠️ 시작 과정</h2>
<p>인스타그램을 둘러보다가 <a href="https://start-ing.kr/">스타팅</a> 이라는 회사를 통해서 여러 분야에 있는 사람들과 프로젝트를 진행할 수 있다고 하길래.. 프로젝트가 필요한 나는 바로 신청을 했었다..!
<img src="https://velog.velcdn.com/images/ssu-uky/post/3389ff2d-ffd6-48be-b5ae-04c16376fd88/image.png" alt=""></p>
<ol>
<li>기획자</li>
<li>디자이너</li>
<li>마케터</li>
<li>프론트 개발자</li>
<li>백엔드 개발자</li>
</ol>
<p>이렇게 각 분야의 사람들 1명씩,
총 다섯명의 사람들이 모여서 한 팀을 이루어서 진행되는 시스템이다.</p>
<p>팀은 스스로 정해야 하는 시스템인게 조금 아쉬웠다.
당연히 주최측에서 정해주는 줄 알았는데..
다행히 다른 분께서 먼저 연락을 주셔서 팀 매칭이 되었다!</p>
<p>중간에 디자이너분과 마케터분이 개인사정으로 나가셔서..
기획자 1명, 프론트엔드 1명, 백엔드 1명(나) 로 진행 되었다.
<del>캡쳐는.. 1기 참여했을 때 캡쳐한거라서 3주라고 되어있지만</del>
2주간 만들어야하는 서비스이기때문에 시작과 동시에 하루하루가 너무 소중했다.</p>
<hr>
<h2 id="🛠️-2주간의-여정-시작">🛠️ 2주간의 여정 시작</h2>
<p>2기의 주제는 <a href="https://www.tmgod.co.kr/">상표의 신</a> 의 새로운 서비스 [특허] 에 대한 서비스를 제작해야한다고 해서 시작하게 되었다.</p>
<p><img src="https://velog.velcdn.com/images/ssu-uky/post/579ae677-0786-4ab7-9d69-02e84ecf804b/image.png" alt=""></p>
<h3 id="기획-1주">기획 (1주)</h3>
<p>일단 특허라는 단어에 대해 이해하는 것 부터 어려워서 모두 다같이 기획을 하는데도 어려움이 있었다.</p>
<p>하루에 몇시간 씩 회의를 하던 우리가 정한건 <strong>특허 가능성 검토..!</strong></p>
<blockquote>
</blockquote>
<ol>
<li>키워드 방식의 발명의 명칭 작성</li>
<li>상담 장벽을 낮추기 위해 로그인 없이 누구나 상담 신청 가능</li>
<li>상담 신청 후 특허청 API와 연동시켜 본인의 아이디어와 비슷한 특허들을 보여줌</li>
</ol>
<p>일단 이렇게 기능을 구현하기로 결정 됨과 동시에, 특허청에 REST API를 신청하였다.</p>
<hr>
<h3 id="개발-시작-1주">개발 시작 (1주)</h3>
<blockquote>
<h3 id="핵심-기능">핵심 기능</h3>
</blockquote>
<ul>
<li>특허청 kipris의 REST API 연동</li>
<li>키워드로 본인의 아이디어와 연관 된 특허 조회</li>
<li>본인이 작성한 글만 조회, 수정, 삭제 가능</li>
</ul>
<p>나는 이 전 프로젝트에서도 그랬듯이 팀원간의 소통이 가장 중요하다고 생각했다.
처음 기획부터 같이 시작해서 데이터베이스도 같이 짜나아갔다.</p>
<p>일단 비대면 프로젝트가 처음인 나는 <strong>서버구축</strong>이 먼저라고 생각하였다.
내가 개발을 하고 서버구축을 해서 드려야 프론트에서 API엔드포인트를 연결 시킬 수 있다고 생각했다.</p>
<p>그래서 기획을 토대로 <a href="https://ssu-uky.notion.site/API-6d90fa43c903490da7e3cb9081eeaa3e?pvs=4">API 문서</a>를 만들고, 프론트엔드 개발자님께 바로 전달 드렸다.</p>
<p>프론트 개발자님도 남은 시간동안 엔드포인트를 이용하여 개발을 해주셨고,
마지막 날에는 제출 전까지 다같이 모여서 개발을 진행했다!</p>
<blockquote>
<p>조금 변경 된 점 : password가 아닌 email로 본인 확인 진행</p>
</blockquote>
<hr>
<h3 id="📍-issue">📍 ISSUE</h3>
<ul>
<li>특허청의 open api를 가져오는 중에 가져오는 양을 설정해도 계속 같은 양만 가져오는 일이 있었다.</li>
</ul>
<pre><code class="language-py">class PossibleBoardWrite(APIView):
    permission_classes = [AllowAny]

    def get(self, request):
        title = request.GET.get(&quot;title&quot;, &quot;&quot;)
        words = title.replace(&quot;,&quot;, &quot;&quot;).split()  # ,와 띄어쓰기 제거

        results = []

        access_key = env(&quot;access_key&quot;)
        # 300개 까지만 보여주기
        kipris_url = &quot;http://plus.kipris.or.kr/openapi/rest/patUtiModInfoSearchSevice/freeSearchInfo?word={word}&amp;accessKey={access_key}&amp;docsCount=300&quot;

        for word in words:
            url = kipris_url.format(word=word, access_key=access_key)
            response = requests.get(url)

            # xml 형식의 데이터를 파싱하고 원하는 정보를 추출하여 json 형식으로 저장
            data = parse_xml(response.text)

            results.extend(data)  # 한번에 보여주는 방식

        total_count = len(results)

        board = {&quot;title&quot;: title, &quot;total_count&quot;: total_count, &quot;results&quot;: results}

        return Response(board, status=status.HTTP_200_OK)</code></pre>
<p>total_count = len(results)
이 부분에서 total_count가 계속 다른 단어를 검색해도 30개만 나왔었는데..</p>
<pre><code class="language-py">kipris_url = &quot;http://plus.kipris.or.kr/openapi/rest/patUtiModInfoSearchSevice/freeSearchInfo?word={word}&amp;accessKey={access_key}&amp;docsCount=300&quot;</code></pre>
<p>마지막 docsCount=300 추가해주니 원하는 만큼(300개) 조회가 되었다..</p>
<p>문서마다 이름이 다 다르게 되어있어서 꼼꼼히 확인을 해야한다..</p>
<hr>
<h3 id="아키텍처architecture">아키텍처(Architecture)</h3>
<p><img src="https://velog.velcdn.com/images/ssu-uky/post/4c84a8b7-983b-4374-8269-740c85b833b3/image.png" alt=""></p>
<hr>
<h2 id="🛠️-프로젝트-후기">🛠️ 프로젝트 후기</h2>
<p>더 보완하고 싶은 부분도 많고 추가하고 싶은 부분도 많지만,
다른 팀에 비해 디자이너와 마케터 없이 3명이서 2주안에 이만큼의 성과를 낸게 대단하다고 생각한다!</p>
<p>점점 더 보완하고, 기능들을 더 추가하면 좋을 것 같다!</p>
<hr>
<h3 id="느낀-점">느낀 점</h3>
<ol>
<li>역시나 기획단계가 탄탄해야 개발도 물 흐르 듯 빠르게 진행된다..</li>
<li>주어진 시간이 2주지만.. 특허라는 개념을 이해하고 알아봐야했기 때문에.. 
첫 주에 기획에만 올인한게 잘했던 것 같기도 하고.. 너무 시간이 지체된 것 같기도 해서 시간이 조금만 더 있었더라면.. 싶다!</li>
</ol>
<hr>
<p>추가로 이 프로젝트도 리팩토링 진행 예정중에 있다!
testcode 추가하고, GitHubActions 이용해서 자동화를 해 볼 예정이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[가까운 1 찾기]]></title>
            <link>https://velog.io/@ssu-uky/%EA%B0%80%EA%B9%8C%EC%9A%B4-1-%EC%B0%BE%EA%B8%B0</link>
            <guid>https://velog.io/@ssu-uky/%EA%B0%80%EA%B9%8C%EC%9A%B4-1-%EC%B0%BE%EA%B8%B0</guid>
            <pubDate>Sat, 15 Jul 2023 18:23:41 GMT</pubDate>
            <description><![CDATA[<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/181898">가까운 1 찾기</a></p>
<h2 id="문제설명">문제설명</h2>
<blockquote>
<p>정수 배열 arr가 주어집니다.
이때 arr의 원소는 1 또는 0입니다.
정수 idx가 주어졌을 때, idx보다 크면서 배열의 값이 1인 가장 작은 인덱스를 찾아서 반환하는 solution 함수를 완성해 주세요.
단, 만약 그러한 인덱스가 없다면 -1을 반환합니다.</p>
</blockquote>
<h3 id="제안사항">제안사항</h3>
<blockquote>
<p>3 ≤ arr의 길이 ≤ 100&#39;000
arr의 원소는 전부 1 또는 0입니다.</p>
</blockquote>
<h4 id="입출력-예">입출력 예</h4>
<p><img src="https://velog.velcdn.com/images/ssu-uky/post/6f191815-5ce9-4d65-905c-597fe9417d31/image.png" alt=""></p>
<h3 id="입출력-예-설명">입출력 예 설명</h3>
<blockquote>
<p>입출력 예 #1
1보다 크면서 원소가 1인 가장 작은 인덱스는 3입니다. 따라서 3을 return 합니다.</p>
</blockquote>
<blockquote>
<p>입출력 예 #2
4번 인덱스 이후에 1은 등장하지 않습니다. 따라서 -1을 return 합니다.</p>
</blockquote>
<blockquote>
<p>입출력 예 #3
3번 인덱스의 값이 1입니다. 따라서 3을 return 합니다.</p>
</blockquote>
<h3 id="처음-내-풀이">처음 내 풀이</h3>
<pre><code class="language-py">def solution(arr, idx):
    answer = 0

    for i,j in enumerate(arr):
    # print(i,j)
    # i = index 번호
    # j = 배열 내 값

    # 인덱스 값이 idx 보다 크고,
    # 배열 내 값이 1인 가장 작은 인덱스 번호 반환
    # 인덱스가 없다면, -1 반환

    # 1. j값이 1인 인덱스 값을 찾는다.
        if j == 1:
            answer = i

            # 2. j가 1인 값 안에서 인덱스(i) 값이 idx 값 보다 크면 i를 반환
            if i &gt;= idx:
                answer = i

                break
            # 2-1. 크지 않다면 -1 반환
            else:
                answer = -1

        else:
            answer = -1

    return answer</code></pre>
<h3 id="도움-받은-풀이">도움 받은 풀이</h3>
<pre><code class="language-py">def solution(arr, idx):
    answer = -1

    for i in range(idx, len(arr)):
        if arr[i] == 1:
            answer = i

            break

    return answer</code></pre>
<h3 id="도움-받은-이유">도움 받은 이유</h3>
<ol>
<li><p>처음 풀이 때 break를 사용 안해서 계속 3번 예시에서 오류가 났었다...
3시간 정도 고민해서 결국 도움을 요청 했는데.. 
break 를 걸어주니.. 바로 해결..!
<img src="https://velog.velcdn.com/images/ssu-uky/post/d792efd8-1b71-408a-93f0-4c700ac98f33/image.png" alt=""></p>
</li>
<li><p>시간 복잡도</p>
</li>
</ol>
<p>+4 점을 받아도 시간이 되게 오래 걸려서 이게 맞나..? 싶었는데
새로운 풀이를 알려주었다..</p>
<h2 id="결론">결론</h2>
<ol>
<li><p>가장 작은 인덱스의 값이라는 조건을 걸지 않았어서 걱정했었는데
새로운 풀이에서 range로 범위를 정해줘서 가장 작은 인덱스의 값의 조건을 정해주었다...</p>
</li>
<li><p>break의 중요성....
여기서든 저기서든 break를 사용해서 멈춰주지않으면.. 결과값이 계속 변경된다..
값이 나왔을 때를 위해서 break로 결과가 나오면 바로 내어주자...</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[ubuntu] django nginx 적용 후 css 깨질 때]]></title>
            <link>https://velog.io/@ssu-uky/ubuntu-django-nginx-%EC%A0%81%EC%9A%A9-%ED%9B%84-css-%EA%B9%A8%EC%A7%88-%EB%95%8C</link>
            <guid>https://velog.io/@ssu-uky/ubuntu-django-nginx-%EC%A0%81%EC%9A%A9-%ED%9B%84-css-%EA%B9%A8%EC%A7%88-%EB%95%8C</guid>
            <pubDate>Fri, 14 Jul 2023 14:50:38 GMT</pubDate>
            <description><![CDATA[<p>ubuntu 환경에서 nginx를 적용하면 css 가 깨진다..
일단 정적파일들을 모아서 이동시켜주면 된다.</p>
<p>manage.py 가 있는 폴더로 이동해서 (거의 루트 폴더)</p>
<pre><code>python manage.py collectstatic</code></pre><p>이렇게 하면 staticfiles 라는 폴더가 뜨면서 모아진다.</p>
<p>그럼 현재 작업폴더에 collectstatic 이라는 폴더가 생성 되는데
이 폴더를 옮겨 주어야 한다!</p>
<pre><code class="language-py">sudo mv staticfiles /var/www/

-&gt; staticfiles 폴더를 /var/www/ 위치로 이동시킨다는 뜻</code></pre>
<p>그리고 nginx 설정으로 가서</p>
<pre><code class="language-py">location /static/ {
    alias /var/www/staticfiles/;
    expires 30d;
    add_header Cache-Control &quot;public, no-transform&quot;;
    }</code></pre>
<p>라는 문구를 추가해준다!!!!!!</p>
<p>그럼 .. 원래 보던 django 가 나온다....</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[ubuntu] 배포 시 첫 단계(feat.poetry) + 추가설정]]></title>
            <link>https://velog.io/@ssu-uky/ubuntu-%EB%B0%B0%ED%8F%AC-%EC%8B%9C-%EC%B2%AB-%EB%8B%A8%EA%B3%84</link>
            <guid>https://velog.io/@ssu-uky/ubuntu-%EB%B0%B0%ED%8F%AC-%EC%8B%9C-%EC%B2%AB-%EB%8B%A8%EA%B3%84</guid>
            <pubDate>Wed, 12 Jul 2023 08:54:03 GMT</pubDate>
            <description><![CDATA[<h3 id="배포-시-첫-단계">배포 시 첫 단계</h3>
<ol>
<li>git clone</li>
<li>내가 작업한 python 버전 설치</li>
<li>가상환경 설치</li>
</ol>
<p>나는 우분투 20.04 / python 3.11 / poetry 사용예정</p>
<pre><code>sudo apt install software-properties-common</code></pre><pre><code>sudo add-apt-repository ppa:deadsnakes/ppa</code></pre><pre><code>sudo apt-get update</code></pre><pre><code>sudo apt-get install python3.11</code></pre><pre><code>python3.11 -V</code></pre><p>이제 3.11 버전이 뜬다! 아래 사진 참고!</p>
<hr>
<p>이제 가상환경 poetry 설치~!</p>
<pre><code>curl -sSL https://install.python-poetry.org | python3 -</code></pre><p><img src="https://velog.velcdn.com/images/ssu-uky/post/0c23fa4b-abff-4fe9-b73e-d9536d389955/image.png" alt=""></p>
<p>핑크색으로 박스친걸 한번 더 터미널에 쳐 주면 path 설정까지 완료!
이제 poetry install이 된다 :)</p>
<h3 id="poetry-실행">poetry 실행</h3>
<p>나 같은 경우는 poetry를 실행하려면, activate 가 있는 위치를 찾아서
하단에 root 먼저 들어간 후 실행을 해야했따.</p>
<p>위치는 대부분 이 즈음에 있다.</p>
<pre><code>/root/.cache/pypoetry/virtualenvs/폴더이름(서버이름)-알파벳-py.3.11/bin/activate</code></pre><p>위치를 찾은 후, 앞에 source 를 붙혀서 터미널에 입력하면 가상환경으로 들어간다!</p>
<pre><code>source /root/.cache/pypoetry/virtualenvs/폴더이름(서버이름)-알파벳-py.3.11/bin/activate</code></pre><p>서버로 접속 후에 python 을 깔아도 poetry shell이 적용되지 않으니.. 확인 필수!!</p>
<h3 id="서버-비밀번호-변경">서버 비밀번호 변경</h3>
<pre><code>sudo passwd &lt;관리자 이름&gt;
sudo passwd root</code></pre><p>이렇게 터미널에 입력하면</p>
<pre><code>new password 를 입력하라고 뜬다.
입력 후, 한번 더 입력하라고 뜬다.
두 번 입력하면 password 변경 완료!</code></pre><p>까먹기 전에 써 놓기<del>!</del>!</p>
<hr>
<h3 id="버전-추가-설정">버전 추가 설정</h3>
<p>+) 추가 1</p>
<blockquote>
<p>위에서 python 3.11까지만 설치하면 버전이 이렇게 뜬다
<img src="https://velog.velcdn.com/images/ssu-uky/post/bd989357-70eb-4a7f-9d56-2cd1f3be2596/image.png" alt=""></p>
</blockquote>
<p>나는 python3 -V 했을 때 default로 3.11이 나오게 하고 싶기 때문에 추가적으로 진행</p>
<pre><code>sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.8 1</code></pre><pre><code>sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.11 2</code></pre><pre><code>sudo update-alternatives --config python3</code></pre><p><img src="https://velog.velcdn.com/images/ssu-uky/post/b7d21df1-138f-4fba-ad44-f864a8ee24d8/image.png" alt=""></p>
<p>이제 python3 -V 하면 3.11 버전 출력</p>
<hr>
<p>+) 추가 2</p>
<p>ubuntu 환경 당 default로 설치되어있는 python 버전이 다르다.</p>
<blockquote>
<p>ubuntu 20.04 는 <strong>python3.8</strong>
ubuntu 22.04 는 <strong>python3.10</strong></p>
</blockquote>
<p>추가 1에서 했던걸 유동적으로 수정하면 됨~!</p>
<hr>
<p>진짜 끄읏 -!</p>
<p><em>다음엔 poetry가 아닌 venv 설치하는 과정 작성해야지..</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[크롤링 시 맥에서 크롬드라이버 오류 날 때]]></title>
            <link>https://velog.io/@ssu-uky/%ED%81%AC%EB%A1%A4%EB%A7%81-%EC%8B%9C-%EB%A7%A5%EC%97%90%EC%84%9C-%ED%81%AC%EB%A1%AC%EB%93%9C%EB%9D%BC%EC%9D%B4%EB%B2%84-%EC%98%A4%EB%A5%98-%EB%82%A0-%EB%95%8C</link>
            <guid>https://velog.io/@ssu-uky/%ED%81%AC%EB%A1%A4%EB%A7%81-%EC%8B%9C-%EB%A7%A5%EC%97%90%EC%84%9C-%ED%81%AC%EB%A1%AC%EB%93%9C%EB%9D%BC%EC%9D%B4%EB%B2%84-%EC%98%A4%EB%A5%98-%EB%82%A0-%EB%95%8C</guid>
            <pubDate>Mon, 26 Jun 2023 04:08:38 GMT</pubDate>
            <description><![CDATA[<p>크롬 드라이버를 다운 받은 후, (크롬 버전에 맞게 / 운영체제에 맞게)</p>
<p>맥에서는 확인되지 않은 어쩌구.. 오류가 뜬다...</p>
<p>크롬 드라이버가 있는 폴더로 들어가서 (cmd 창으로 들어가서 폴더로 진입)</p>
<blockquote>
<p>xattr -d com.apple.quarantine chromedriver</p>
</blockquote>
<p>를 입력하면 해결 !</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[ubuntu] 우분투 20.04 sql 버전 업데이트]]></title>
            <link>https://velog.io/@ssu-uky/%EC%9A%B0%EB%B6%84%ED%88%AC-20.04-sql-%EB%B2%84%EC%A0%84-%EC%97%85%EB%8D%B0%EC%9D%B4%ED%8A%B8</link>
            <guid>https://velog.io/@ssu-uky/%EC%9A%B0%EB%B6%84%ED%88%AC-20.04-sql-%EB%B2%84%EC%A0%84-%EC%97%85%EB%8D%B0%EC%9D%B4%ED%8A%B8</guid>
            <pubDate>Mon, 12 Jun 2023 17:44:00 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>sudo apt-get install python3.11-dev default-libmysqlclient-dev
poetry shell
poetry add mysqlclient</p>
</blockquote>
<p>우분투 20.04 버전 사용 중에
파이썬은 3.11 버전으로 맞췄었고,
mysql도 파이썬 버전에 맞춰야했었는데...
한창 고생하다가...</p>
<p>해결...</p>
<hr>
<p>+) 추가</p>
<p>venv로 실행 했을 때는 계속 이런 에러가 떴다</p>
<pre><code>Exception: Can not find valid pkg-config name.</code></pre><p>아래의 명령어를 설치 한번 더 하고.. 해결...</p>
<blockquote>
<p>sudo apt install pkg-config</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[배열 만들기 4]]></title>
            <link>https://velog.io/@ssu-uky/%EB%B0%B0%EC%97%B4-%EB%A7%8C%EB%93%A4%EA%B8%B0-4</link>
            <guid>https://velog.io/@ssu-uky/%EB%B0%B0%EC%97%B4-%EB%A7%8C%EB%93%A4%EA%B8%B0-4</guid>
            <pubDate>Mon, 12 Jun 2023 17:06:22 GMT</pubDate>
            <description><![CDATA[<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/181918">배열 만들기 4</a></p>
<h2 id="문제-설명">문제 설명</h2>
<p>정수 배열 arr가 주어집니다. arr를 이용해 새로운 배열 stk를 만드려고 합니다.</p>
<p>변수 i를 만들어 초기값을 0으로 설정한 후 i가 arr의 길이보다 작으면 다음 작업을 반복합니다.</p>
<p>만약 stk가 빈 배열이라면 arr[i]를 stk에 추가하고 i에 1을 더합니다.
stk에 원소가 있고, stk의 마지막 원소가 arr[i]보다 작으면 arr[i]를 stk의 뒤에 추가하고 i에 1을 더합니다.
stk에 원소가 있는데 stk의 마지막 원소가 arr[i]보다 크거나 같으면 stk의 마지막 원소를 stk에서 제거합니다.
위 작업을 마친 후 만들어진 stk를 return 하는 solution 함수를 완성해 주세요.</p>
<h3 id="제한사항">제한사항</h3>
<ul>
<li>1 ≤ arr의 길이 ≤ 100,000</li>
<li><ul>
<li>1 ≤ arr의 원소 ≤ 100,000</li>
</ul>
</li>
</ul>
<h3 id="입출력-예">입출력 예</h3>
<p><img src="https://velog.velcdn.com/images/ssu-uky/post/2c66e5b2-e73e-438d-b5f3-f73cd97eb677/image.png" alt=""></p>
<h2 id="내-풀이">내 풀이</h2>
<pre><code class="language-py">def solution(arr):
    stk = []

    # 변수 i 초기화
    i = 0

    # i &lt; len(arr) 라면, 무한반복
    while i &lt; len(arr):
        # stk가 빈 배열일 때, stk에 arr[i]를 추가하고 i+1 하기
        if stk == []:
            stk.append(arr[i])
            i += 1
        # stk이 빈 배열이 아니고, stk의 마지막 원소가 arr[i]보다 작으면, arr[i]를 stk뒤에 추가하고, i+1 하기
        elif stk[-1] &lt; arr[i]:
            stk.append(arr[i])
            i += 1
        else:
            stk.pop(-1)

    return stk</code></pre>
<p>여기서 헷갈렸떤 건,,,
while문을 쓸 생각을 못했다...</p>
<p>while문에도 조건이 걸려있기 때문에 break를 안 걸어 줘도 되는 점도 참고 <del>!!</del>!!!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[콜라츠 수열 만들기]]></title>
            <link>https://velog.io/@ssu-uky/%EC%BD%9C%EB%9D%BC%EC%B8%A0-%EC%88%98%EC%97%B4-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@ssu-uky/%EC%BD%9C%EB%9D%BC%EC%B8%A0-%EC%88%98%EC%97%B4-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Mon, 12 Jun 2023 17:04:28 GMT</pubDate>
            <description><![CDATA[<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/181919">콜라츠 수열 만들기</a></p>
<h2 id="문제-설명">문제 설명</h2>
<p>모든 자연수 x에 대해서 현재 값이 x이면 x가 짝수일 때는 2로 나누고, x가 홀수일 때는 3 * x + 1로 바꾸는 계산을 계속해서 반복하면 언젠가는 반드시 x가 1이 되는지 묻는 문제를 콜라츠 문제라고 부릅니다.</p>
<p>그리고 위 과정에서 거쳐간 모든 수를 기록한 수열을 콜라츠 수열이라고 부릅니다.</p>
<p>계산 결과 1,000 보다 작거나 같은 수에 대해서는 전부 언젠가 1에 도달한다는 것이 알려져 있습니다.</p>
<p>임의의 1,000 보다 작거나 같은 양의 정수 n이 주어질 때 초기값이 n인 콜라츠 수열을 return 하는 solution 함수를 완성해 주세요.</p>
<h3 id="제한사항">제한사항</h3>
<ul>
<li>1 ≤ n ≤ 1,000</li>
</ul>
<h3 id="입출력-예-및-설명">입출력 예 및 설명</h3>
<p><img src="https://velog.velcdn.com/images/ssu-uky/post/22beb084-0b77-4c15-ad29-38a1fac2d01f/image.png" alt=""></p>
<h2 id="풀이">풀이</h2>
<pre><code class="language-py">def solution(n):
    answer = []

    # n이 1이 아닐 때,
    while n != 1:
        # 루프 도는 동안 answer에 저장
        answer.append(n)

        # n이 짝수일 때
        if n%2 == 0:
            n = n//2

        # n이 홀수일 때
        else:
            n = 3*n+1

    # if문에서 나온 n들을 answer에 저장
    answer.append(n)

    return answer</code></pre>
<p>** 콜라츠 수열 이라는 것 자체가 어떤 수를 대입해도 무한루프를 돌리면 마지막에는 1이 출력된다고 한다... 신기한 .. 수학의 세계...</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Open AI 사용하기 (Feat.  RateLimitError)]]></title>
            <link>https://velog.io/@ssu-uky/Open-AI-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-feat.rate-limit-error</link>
            <guid>https://velog.io/@ssu-uky/Open-AI-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-feat.rate-limit-error</guid>
            <pubDate>Sun, 04 Jun 2023 18:55:34 GMT</pubDate>
            <description><![CDATA[<p>Open AI를 사용해서 챗봇같은 느낌으로 고민 상담 봇을 만드려고 하는 중이였다..
가입도 하고 API Key도 발급 받고.. 다 했다고 생각했는데..</p>
<blockquote>
<p>&quot;You exceeded your current quota, please check your plan and billing details&quot;</p>
</blockquote>
<p>라는 오류가 계속 발생했었다...</p>
<p><img src="https://velog.velcdn.com/images/ssu-uky/post/d5fa1215-a8bd-48b4-9ab8-f2c346fe2146/image.png" alt="">
GPT는 이렇게 말해주는데...</p>
<blockquote>
<p>내가 이게 무슨 해답인지.. 나랑 별개라고 생각했던 이유</p>
<p>1번. 할당량을 사용한 적이 없음
2번. GPT를 유료버전을 사용하고 있음</p>
</blockquote>
<p>막상 하단에 얼마나 사용했는지 확인하는 링크 들어가보면
<a href="https://platform.openai.com/account/usage">https://platform.openai.com/account/usage</a></p>
<p><img src="https://velog.velcdn.com/images/ssu-uky/post/8df907e0-9335-4cc1-a605-6cef1757cd39/image.png" alt="">
사용한게 없다고 나오는데...
대체 왜 안되는지 삽질만 하다가...</p>
<p>저번에 <a href="https://www.ncloud.com/">네이버클라우드플랫폼</a> 에서도
결제방식을 입력 안해서 크레딧이 안들어온게 생각났다...</p>
<p>그래서 openai 에서 카드 번호 입력하니까 ^^.. 바로 해결 ! ^^...~
<a href="https://platform.openai.com/account/billing/overview">https://platform.openai.com/account/billing/overview</a></p>
<p>한 달에 $120.00 은 무료로 제공하니까...
최댓값과 알림값을 과금 나오지 않도록.. 잘 조절하면 될 것 같다 :)</p>
<h3 id="결론">결론</h3>
<blockquote>
<p>결론은 GPT의 유료버전을 사용하는것과 open ai 를 사용하는 것과는 별개이다...
카드번호를 별개로 입력해야함...</p>
</blockquote>
<p>그래도.. 몇일간의 삽질 해결로 인해 집 나갔던 의욕들을 조금은 데려온 듯 하다.. 🥹</p>
<p><img src="https://velog.velcdn.com/images/ssu-uky/post/f781939b-3a1a-4202-a765-e58cf73e3494/image.jpeg" alt="">
+) open ai에 카드 등록과 동시에 5달러가 결제 되는 것 같다...!</p>
]]></description>
        </item>
    </channel>
</rss>