Model.objects.get()Model.objects.filter() 모두 장고와 연결된 데이터베이스에서 조건에 맞는 데이터를 리턴하고 싶을 때 사용한다. 그러나 두 메소드는 엄연한 차이가 있다. 

 

쿼리셋(QuerySet)

둘의 차이를 이해하기 위해서는 쿼리셋이 무엇인지를 먼저 알아봐야 한다. 

쿼리셋(Queryset)이란 장고와 연결된 데이터베이스에 저장된 객체들의 모임을 의미한다. 쿼리셋은 SQL문으로 치면 SELECT문과 같다. 여기에 WHERE, LIMIT 등의 여러 필터를 사용해서 원하는 데이터만 포함한 쿼리셋을 만들 수 있다. 

+ 앞으로 '쿼리를 날린다'는 표현을 사용할 건데, '쿼리를 날린다' = '데이터베이스에 연결한다' 라고 보면 된다. 

 

쿼리셋과 데이터베이스 접근은 다르다. (Querysets are lazy)

기본적으로 쿼리셋은 메모리의 일종인 캐시(cache)를 사용해서 데이터베이스에 접근을 최소화 하려고 한다. 따라서 만약 어떤 메소드가 쿼리셋을 리턴하고 그 리턴된 쿼리셋이 캐시 메모리를 포함한다면, 나중에 같은 정보가 필요할 때 기존에 리턴된 쿼리셋을 사용할 수 있다. 

 

쿼리셋이 만들어지거나 쿼리셋에 추가적인 필터 메소드를 적용한다고 해서 항상 데이터베이스에 쿼리를 날리는 것이 아니다. 쿼리셋이 만들어진 이후, 쿼리셋을 계산(evaluate)하는 메소드가 실행되면 그 때 쿼리를 날리게 된다. 

 

쿼리셋을 계산하는 메소드

이 메소드를 사용할 때는 데이터베이스에 쿼리를 날리게 된다. 

  • 반복
  • (인덱스 기반의) 슬라이싱
  • 피클링/캐싱
  • 쿼리셋을 출력할 수 있는 문자열로 반환: repr()
  • 쿼리셋의 객체 수(길이) 리턴: len()
  • 쿼리셋을 리스트 타입으로 변경: list()
  • 쿼리셋 안에 객체가 존재하는지 판단: bool()

 

get()filter()의 차이

🌟SQL 쿼리의 차이

장고 내부에서 생성된 쿼리셋을 계산할 때는 데이터베이스에 쿼리를 날려야 한다. 즉 쿼리 메소드는 SQL문으로 변환될 수 있다. filter() 메소드의 경우 다음과 같이 변환될 수 있다. 

 

- ORM

Restaurant.objects.filter(name="seoul")

- SQL

SELECT 'id', 'name', 'category', 'email', 'menu'
FROM 'restaurant' WHERE 'restaurant'.'name' = 'seoul'

 

그러나 get() 메소드의 경우는 filter() 메소드와 달리 별다른 SQL 메소드로 변환될 수 없다. 

대신 filter() 메소드에 부가적인 처리를 해서 나타낼 수 있다. 

 

-ORM

Restaurant.objects.get(name='seoul')

-Code

rest = Restaurant.objects.filter(name='seoul')

if len(rest) == 1:
	return rest[0]
else:
	raise Exception

즉 get() 메소드는 filter() 메소드에 부가적인 처리를 한 결과를 리턴한다. 그러므로 같은 코드를 실행해도 filter()의 속도가 get()보다 빠르다.

 

뿐만 아니라, 인덱싱(rest[0])의 경우 쿼리셋에 해당하는 인덱스가 없다면 오류를 발생시킨다. 따라서 filter()는 조건에 해당하는 데이터의 개수에 상관 없이 결과를 리턴하지만, get()은 조건에 해당하는 데이터가 1개가 아닌 이상 오류를 반환한다. 

 

그러므로 get()은 반드시 한 개의 데이터만 리턴하고, 하나가 아니면 오류를 발생시킬 때만 사용하는 것이 더 효율적이라고 볼 수 있겠다! 

 

🌟쿼리셋을 리턴한다 vs 리턴하지 않는다

쿼리셋을 리턴하지 않는 메소드의 경우, 쿼리셋이 없기 때문에 캐시도 갖고 있지 않다. 그렇기 때문에 이 메소드들은 한 번 호출될 때마다 데이터베이스에 쿼리를 날리게 된다. get()은 쿼리셋을 리턴하지 않는 메소드들 중 하나이다. 

반면 filter()는 쿼리셋을 리턴한다. 따라서 filter()를 사용한다고 바로 쿼리를 날리는 것이 아니다. 그래서 메소드를 여러 번 사용할 경우, get() 보다는 filter()가 더 빠르다. 

 

Project라는 모델이 있다고 가정할 때, 아래의 두 코드의 성능은 다르다. 

# get()
p1 = Project.objects.get(id=1)
print(p1)
p2 = Project.objects.get(id=2)
print(p2)
p3 = Project.objects.get(id=3)
print(p3)
p4 = Project.objects.get(id=4)
print(p4)
# filter()
proj = Project.objects.filter(id__lte=4)
for p in proj:
	print(p)

위의 코드는 get을 사용하여 총 4번 데이터베이스에 쿼리를 날리지만, 아래 코드는 filter()를 사용해 쿼리셋을 생성하고, for문을 사용해서 쿼리셋 안의 객체를 문자열로 출력할 때만 데이터베이스에 쿼리를 날린다. 

 

따라서 순서(ordering)가 별 상관이 없다면, get()을 여러 번 사용하는 것 보다는 filter()를 사용해서 적합한 쿼리셋을 생성한 뒤, for문 등을 이용해서 데이터베이스 접근을 최소화하는 것이 더 성능이 좋다. 

 

🌟여러 개의 데이터를 포함할 수 있다 vs 하나의 데이터만 포함한다

또한 filter()는 쿼리셋을 리턴하기에 여러 개의 데이터를 쿼리셋으로 받을 수 있지만, get()은 하나의 데이터만 받을 수 있다. 만약 get() 실행 시 해당하는 데이터가 없다면 Model.DoesNotExist 에러가 발생하고, 또는 해당하는 데이터가 여러 개라면 Model.MultipleObjectsReturned 에러가 발생한다. 또한 해당하는 데이터가 여러 개인 경우, 오류가 발생하기 전에 쿼리의 실행 속도가 상당히 느려지기도 한다. 

 

따라서 get()을 사용해야 한다면 반드시 unique한 컬럼명 또는 인덱스 컬럼명, primary key 등을 사용해서 해당하는 데이터가 여러 개 나오지 않도록 주의하자. 

 

 

참고한 포스트

Django에서 DB 액세스 최적화하기 – Myungseo Kang

QuerySet API reference | Django 문서 | Django (djangoproject.com)

Making queries | Django documentation | Django (djangoproject.com)

django - filter().exists(), Q() 객체, F() 객체 (velog.io)

 

'server-side > Django' 카테고리의 다른 글

signals  (0) 2023.06.21
Model.select_related() vs Model.prefetch_related()  (0) 2022.07.11
models: on_delete  (0) 2022.07.05
admin: Inline, InlineModelAdmin  (0) 2022.07.02
conda 사용해서 가상환경 만들기  (0) 2022.06.29

Cron이란?

지정된 시간에 지정한 업무를 해 주는 프로그램으로, 주로 리눅스 운영체제에서 많이 사용한다. 

cron에 등록된 업무들은 cron 디렉토리 내부의 파일에 저장된다.

 

cron 디렉토리

/var/spool/cron/crontabs 또는 /var/spool/cron/

 

그러나 cron으로 등록된 업무를 추가, 수정 및 변경하고 싶다면 직접 파일을 변경해서는 안 된다. 터미널에서 crontab 이라는 명령어를 사용해서 변경하자. 

 

 

cron 파일의 구성

cron 파일은 명령어, 환경설정, 주석 이렇게 세 종류의 라인으로 구분된다. 

 

cron 스케줄링

cron에 업무를 등록해서 수행하게 하려면, 어떤 시간에 어떤 업무를 수행할지 알려주어야 한다. 

{분 시간 일 월 요일} {수행할 업무가 저장된 파일 경로}

 

분, 시간, 일, 월, 요일은 모두 숫자로 작성하고, 파일 경로는 해당 cron shell의 경로에서 상대 경로로 입력한다. 

- 분: 0-59

- 시간: 0-23

- 일: 1-31

- 월: 1-12

- 요일: 0-7 (일요일이 0 또는 7이다)

 

-,를 사용해서 각 필드를 연속된 값, 또는 각각 떨어진 값들로 지정하는 것도 가능하다. 

0 0 1,2 * *		# 매월 1일과 2일 정각에 실행
0 0 * * 1-3		# 매주 월, 화, 수 정각에 실행

 

매번 진행하다 보면 cron 실행 시간이 유효하지 않을 수 있다. 

ex) 매월 31일에 실행했을 때, 6월 31일은 없다. 

이 경우, 유효하지 않은 경우는 업무를 진행하지 않는다. 

즉 매월 31일에 실행한다고 입력하면 실제로는 2, 4, 6, 9, 11월에는 업무가 실행되지 않는다. 

 

crontab 명령어 사용법

1) 변경

해당 명령어 뒤에 변경할 내용을 입력하면 그대로 변경된다. 

$ crontab -e

2) 현재 명령어 보기

cron에 등록된 명령들을 변경하지 않고 조회만 할 수 있다. 

$ crontab -l

3) 삭제

현재 접속한 유저 계정으로 등록된 모든 cron 명령들을 삭제한다. 

$ crontab -r

4) (root 유저로 접속 시) 다른 유저의 crontab 업무 변경/조회/삭제

$ crontab -u certainUser -e		# 변경
$ crontab -u certainUser -l		# 조회
$ crontab -u certainUser -r		# 삭제

 

cron 주석(comment)

여느 프로그래밍 언어처럼 cron 파일에도 부가적인 설명 등을 추가할 수 있는 주석 기능이 있다. 

주석은 라인 단위로만 달 수 있고, 라인 중간부터 주석을 선언하는 것은 불가능하다. 

주석을 달려면 해당 라인의 첫 문자를 # 으로 시작하면 된다. 

 

cron 환경설정

cron 프로그램의 실행에 관여하는 환경변수를 설정하거나, 기존 환경변수의 값을 바꿀 수 있다. 

cron 파일은 위에서부터 아래로 읽기 때문에, 처음부터 어떤 변수를 특정 값으로 정해 두고 싶다면 해당 환경설정 명령어를 맨 윗 줄에 위치시키면 된다. 

 

✔️SHELL

cron 프로그램이 작동하는 shell의 위치를 저장한 변수이며, 기본값은 /bin/sh 으로 설정되어 있다. 

$ SHELL = /bin/sh

 

✔️MAILTO

cron 프로그램은 등록한 작업을 수행하면 기본값으로 해당 작업을 등록한 유저의 계정으로 메일을 보내도록 되어 있다. 

MAILTO = {해당 유저의 메일 주소}로 되어 있다. 

만약 메일을 받고 싶지 않다면 MAILTO = "" 으로 바꿔 주자. 

 

그런데 메일을 안 받으면 수행된 cron 작업에 대한 메시지는 저장되지 않고 사라진다. 

따라서 다른 방법을 사용하는 것이 일반적이다. 

 

1. cron 업무 기록을 파일에 저장하기

(1) overwrite - 덮어쓰기

{cron 작업 내용} echo "메시지" > 저장할 파일명.log

0 * * * * echo "Hourly message." > message.log

해당 파일의 내용을 덮어쓴다. 해당 cron 업무가 이후에 또 수행되면, 해당 파일의 내용을 새 기록으로 대체한다. 

따라서 cron 업무 내용을 누적해서 기록하고 싶다면 덮어쓰기보다는 이어서 쓰는 것이 좋다. 

 

(2) append - 이어쓰기

{cron 작업 내용} echo "메시지" >> 저장할 파일명.log

0 * * * * echo "Hourly message." >> message.log

 

2. cron 업무 중 오류가 난 경우만 파일에 저장하기

{cron 업무 내용} > /dev/null

/dev/null 은 특정 경로라기보다는 리눅스 운영체제에만 있는 특별한 종류의 파일이다. 해당 파일에 기록된 내용은 기록된 즉시 바로 삭제된다. 그러므로 사용자는 오류가 난 경우가 아니면 알림이나 기록을 받지 않을 수 있다. 

 

 

참고한 포스트

Working with Cron Jobs - HostDime Knowledge Base

 

'server-side > server' 카테고리의 다른 글

Mac 환경설정  (0) 2024.07.15
Software Release Life Cycle  (0) 2023.07.15
OAuth 2.0 기본원리  (0) 2022.09.26
인증(Authentication)  (0) 2022.07.14
Git: clone, single-branch, checkout  (0) 2022.06.28

models.ForeignKey(on_delete={})

models.ForeignKey(참조할 모델, on_delete={참조하는 인스턴스가 삭제될 시 해당 인스턴스를 처리하는 방법})

on_delete 옵션은 해당 인스턴스가 참조하는 인스턴스가 삭제되었을 시, 해당 인스턴스를 어떻게 처리할지를 지정한다. 

 

1) models.CASCADE

해당 인스턴스가 참조하는 인스턴스가 삭제된 경우, 해당 인스턴스도 같이 삭제한다. 

 

2) models.PROTECT

해당 인스턴스가 참조하는 인스턴스를 삭제하려고 할 때 ProtectedError를 발생시킨다. 

 

3) models.RESTRICT

해당 인스턴스가 참조하는 인스턴스를 삭제하려고 할 때 RestrictedError를 발생시킨다. 

 

두 옵션 모두 에러를 발생시키지만 서로 다르다. 

 

 

🗒️PROTECT와 RESTRICT 옵션의 차이점

해당 인스턴스 A, 해당 인스턴스가 참조하는 인스턴스 B, B가 참조하는 또 다른 인스턴스 C라고 하자.

이때 A는 B, B는 C 인스턴스를 참조하므로, A와 B는 ForeignKey 필드를 갖고 있다. 

 

[1] on_delete=PROTECT 인 경우

A는 on_delete=PROTECT, B는 on_delete=CASCADE라고 해 보자. 

 

B를 삭제하려고 한다면 A의 on_delete=PROTECT 옵션 때문에 B가 삭제되지 않고 ProtectedError가 발생한다. 

C를 삭제한다면, B는 on_delete=CASCADE 이므로 원래는 같이 삭제되어야 한다. 

그러나 B를 참조하는 A는 on_delete=PROTECT 이므로 B는 삭제될 수 없다. 

따라서 C를 삭제하려고 해도 ProtectedError가 발생한다. 

 

[2] on_delete=RESTRICT 인 경우

A는 on_delete=RESTRICT, B는 on_delete=CASCADE라고 해 보자. 

 

B를 삭제하려고 한다면 A의 on_delete=RESTRICT 옵션 때문에 B가 삭제되지 않고 RestrictedError가 발생한다.

C를 삭제한다면, B는 on_delete=CASCADE 이므로 같이 삭제된다. 

즉 RESTRICT 옵션은 직접적으로 B를 삭제하는 것은 제한하지만, B가 참조하는 다른 인스턴스에 의해서 B가 삭제되는 것은 제한하지 않는다. 

 

4) models.SET_NULL

해당 인스턴스가 참조하는 인스턴스가 삭제될 경우, 해당 인스턴스의 값을 NULL로 바꾼다. 

이때, 반드시 해당 인스턴스의 옵션이 null=True 으로 되어있어야 한다!

 

5) models.SET_DEFAULT

해당 인스턴스가 참조하는 인스턴스가 삭제될 경우, 해당 인스턴스의 값을 Default로 지정된 값으로 바꾼다. 

그러려면 반드시 해당 인스턴스의 default 값이 지정되어 있어야 한다!

 

6) models.SET({value})

해당 인스턴스가 참조하는 인스턴스가 삭제될 경우, 해당 인스턴스의 값을 SET 안의 값으로 바꾼다.

그러려면 반드시 SET의 괄호() 안에 값을 지정해 주어야 한다. 

 

7) models.DO_NOTHING

별다른 추가 처리를 하지 않는다. 

 

 

참고한 포스트

Model field reference | Django documentation | Django (djangoproject.com)

 

Inline

모델 A가 모델 B를 ForeignKey로 가질 때, 모델 A는 모델 B에 의존한다. 

모델 A의 각 데이터마다 해당하는 모델 B의 데이터를 보고 싶을 때, inline을 사용한다. 

 

# models.py
class Home(models.Model):
	id = models.IntegerField()
	address = models.CharField()

class Person(models.Model):
	id = models.IntegerField()
	name = models.CharField()
	home = models.ForeignKey(Home, on_delete=models.CASCADE)
# admin.py
class PersonInline(admin.StackedInline):
	model = Home	# 해당 클래스가 외래키로 갖는 모델 입력
    
class HomeAdmin(admin.ModelAdmin):
	inlines = [PersonInline]	# 해당 클래스를 참조하는 다른 inline 클래스 입력

 

예시에서는 Person이 Home을 ForeignKey로 갖는다.

하나의 home 인스턴스를 참조하는 person 객체는 여러개일 수 있다. 

만약 각각의 home을 참조하는 person 객체들을 한 번에 보고 싶다면 inline을 활용하면 된다. 

 

InlineModelAdmin

장고에서도 inline을 사용하기 위한 InlineModelAdmin 클래스를 제공한다. 

(InlineModelAdmin은 ModelAdmin의 하위 클래스이다.)

InlineModelAdmin 클래스는 두 개의 하위 클래스인 StackedInline, TabularInline으로 구성되어 있는데, 두 클래스의 차이는 렌더링에 사용되는 템플릿의 차이 정도라고 봐도 무방하다. 

 

*렌더링(rendering):

작성한 웹사이트 코드를 사용자가 보는 웹 페이지로 바꾸는 과정. 

렌더링 엔진을 사용하여 렌더링을 한다. 

 

+) 또한 각 인스턴스를 참조하는 inline은 개별 데이터를 조회하는 화면에서 볼 수 있다. 

 

 

InlineModelAdmin options

InlineModelAdmin의 옵션 중 ModelAdmin의 필드와 다른 것, 재정의한 필드 등을 살펴보자. 

 

1) models

Inline 클래스가 어떤 모델의 데이터를 나타내는지를 입력한다. 

 

2) can_delete

데이터 조회 페이지가 아니라 inline이 나온 페이지에서도 데이터를 삭제할 수 있는지를 결정한다. 

기본값은 True이며 이 경우 inline에서 바로 데이터를 삭제할 수 있다. 

False로 입력하면 inline에서는 데이터를 삭제할 수 없고, inline에 해당하는 클래스(모델)의 데이터 조회 페이지에서 데이터를 삭제할 수 있다. 

 

3) fields

inline에서도 필드를 선택적으로 보여줄 수 있다. 

 

4) exclude

fields와 기능은 같은 반대 옵션이다. inline에서는 사용자에게 이 안에 입력한 필드만 제외하고 보여준다. 

 

5) inlines

inline 클래스에서도 또 다시 inline을 지정할 수 있다. 

 

6) fk_name

해당 inline이 나타내는 클래스에 여러 개의 ForeignKey 필드가 있을 때 사용한다.

여러 개의 ForeignKey 필드 중에서 어떤 필드를 참조하여 inline을 생성할지를 결정한다. 

# models.py
class Request(models.Model):

    user = models.ForeignKey(User, on_delete=models.CASCADE)
    project = models.ForeignKey(Project, on_delete=models.CASCADE)
    request_state = models.IntegerField()
    name = models.CharField()
    deadline = models.DateTimeField()
    contents = models.TextField()
    price = models.IntegerField()


# admin.py
class RequestInline(NestedStackedInline):
    model = Request
    fk_name = 'project'

RequestInline 클래스는 Request 모델에 대한 inline을 담당한다. 

그러나 Request 모델은 2개의 ForeignKey(User, Project)를 갖고 있다. 

따라서 inline을 생성할 때 개별 User에 대해서 inline을 생성할지, 개별 project에 대해서 inline을 생성할지를 정해 주어야 한다. 

여기서는 fk_name = 'project' 으로 project 필드를 기준으로 inline을 생성한다고 지정했다. 

 

7) max_num

하나의 데이터를 조회할 때, 최대 몇 개의 inline 데이터를 표시할지를 지정한다. 

 

8) formfield_overrides

딕셔너리 형태의 값을 받는다. 

모델에서 정의한 특정 필드를 관리자 페이지에서만 지정된 형식으로 나타낼 수 있게 해 준다. 

 

# models.py
class Person(models.Model):
	id = models.BigIntegerField()
	name = models.CharField(max_length=30)
	introduce = models.CharField(max_length=500)
    
# admin.py
class PersonAdmin(admin.ModelAdmin):
	formfield_overrides = {
		models.BigIntegerField: {'widget': Textarea(attrs={'rows':1, 'cols':15})}
		models.BigIntegerField: {'widget': Textarea(attrs={'rows':2, 'cols':25})}
	}

모델 Person을 조회하는 관리자 페이지에서는 models.BigIntegerField 타입인 필드를 Textarea()의 형식으로 나타낼 수 있다. (CharField도 마찬가지이다. )

 

 

<잘 모르겠는 options> - 다음에 공부하기!

-formset

-form

-extra

 

 

참고한 포스트

The Django admin site | Django documentation | Django (djangoproject.com)

 

가상환경을 설치하는 방법은 anaconda, pip 등 여러 가지가 있다. 

오늘은 anaconda와 pip을 둘 다 사용해서 가상환경을 만들어 보자. 

pip는 저번에 구체적으로 다루었으니, 이번에는 conda를 사용해서 가상환경을 만든 뒤 그 안에서 pip를 사용해 볼 것이다. 

 

anaconda와 pip은 모두 파이썬을 사용하는 가상환경을 만들어 준다는 점에서 동일하지만, anaconda에서 사용 가능한 라이브러리와 pip에서 사용 가능한 라이브러리가 다르다. 

(물론 numpy처럼 둘 다에서 사용 가능한 라이브러리도 있다.)

 

anaconda와 pip의 차이

anaconda와 pip이 어떻게 다른지를 알아보기 위해서 각 시스템의 특징을 보자. 

 

pip는 파이썬 환경에서만 사용할 수 있는 패키지가 포함된다.

반면 conda는 파이썬 외의 C, C++, Java 등에서도 사용 가능한 패키지도 포함된다. 

 

또한 pip의 패키지들은 소스 패키지라서 아직 빌드를 하지 않은 상태이다. 즉 빌드를 하다가 예외적인 상황으로 오류가 발생할 가능성이 있다. 

반면 conda의 패키지들은 사용자의 운영체제에 맞춰서 이미 빌드가 된 상태이고, 한 패키지의 버전을 변경하면 그 패키지와 의존관계가 있는 다른 패키지의 버전도 맞춰서 변경해 준다. 

 

conda의 단점을 얘기한 것 같은데, 그렇다기보다는 두 시스템이 다르다고 보면 될 것 같다. 

pip의 장점 중에서는 conda보다 용량이 가벼운 패키지들이 많다는 의견도 있다. 

 

conda의 패키지를 C나 Java에서 사용할 수 있는 이유

이는 파이썬 언어의 특징과 관련이 있다. 

파이썬은 C, C++와 잘 결합되는 언어이다.

일부 파이썬 라이브러리의 경우, C나 C++로 라이브러리를 개발한 뒤, 파이썬 언어를 사용해서도 해당 라이브러리를 다룰 수 있게 만들었다.

그래서 conda의 패키지를 파이썬과 C++ 환경 모두에서 사용할 수 있다. 

 

 

본격 설치하기

 

시작 전에, anaconda 공식 홈페이지에서 anaconda를 다운 받고 환경변수 설정을 마쳐야 한다. 

제대로 잘 되었다면, 윈도우 cmd 기준으로

conda --version

이렇게 입력했을 때 오류 없이 anaconda의 버전이 뜰 것이다. 

 

conda 가상환경 설치하기

지금부터는 cmd에서 conda라는 anaconda 환경변수를 이용해서 작업할 것이다. 

conda create -n {가상환경 이름} 

conda create -n condaenv

 

pip와 마찬가지로 특정 버전의 파이썬을 사용하는 가상환경을 만들고 싶다면 뒤에 python={버전} 을 붙여준다. 

conda create -n {가상환경 이름} python={파이썬 버전}

conda create -n condaenv python=3.6

당연한 말이지만 여기서 명시한 파이썬 버전 파일이 로컬 PC에 있어야 한다. 

 

conda 가상환경 삭제하기

만약 가상환경을 잘못 만들었다면 삭제해야 한다. 

conda remove -n {환경변수 이름} --all

conda remove -n condaenv --all

가상환경의 특정 부분만 삭제하려는 것이 아니라면 명령어 뒤에 반드시 --all 을 붙여주자. 그래야 환경 전체가 잘 삭제된다. 

환경이 완전히 삭제되지 않는 경우, 다음에 같은 이름으로 가상환경을 만든다면 conda 파일이 아닌 해당 이름의 파일이 이미 해당 디렉토리에 존재한다는 식의 에러가 뜬다. 

 

conda 가상환경 실행하기

아무튼 가상환경이 잘 만들어졌다면 이제 가상환경을 실행해야 한다. 

conda activate {가상환경 이름}

conda activate condaenv

 

CommandNotFoundError 오류가 난다면? 

나는 conda를 처음 사용했었는데, 처음에 이 명령어를 입력하니 오류가 났다. 

 

CommandNotFoundError: your shell has not been properly configured to use 'conda deactivate'

 

1) 윈도우

맨 처음 conda 가상환경을 만들었다면, 바로 실행하지 말고 conda init 명령어를 입력한다. 

그러면 conda와 Shell(여기서는 cmd)이 서로 연결되기 위해서 초기화 작업을 실행한다. 

이 작업이 끝나면 초기화 작업이 잘 반영되도록 cmd를 끄고 새 창을 열라는 말이 나온다. 

 

2) 맥, 리눅스

다른 커맨드를 입력해서 문제를 해결할 수 있다. 

source ~/anaconda3/etc/profile.d/conda.sh
conda activate my_env

 

conda 패키지 설치하기

conda install {설치할 패키지 이름}

conda install package-name

 

만약 기본 채널(channel)이 아니라 다른 채널의 패키지를 설치하고 싶다면 -c 옵션을 추가하자. 

conda install -c {채널 이름} {설치할 패키지 이름}

conda install -c conda-forge pythonocc-core occt

 

🗒️채널(Channel)

conda 패키지를 저장하는 저장소. conda에는 여러 개의 원격 저장소(채널)가 존재한다. 

예를 들어 다운받으려는 패키지가 A 채널에 있다면, -c 옵션으로 A 채널에서 패키지를 다운로드한다고 명시해 주어야 한다. 

대표적인 conda 채널에는 conda-forge가 있다. 

 

--append: 채널 추가하기

어떤 채널을 통해서 패키지를 다운 받고 싶다면 우선 그 채널을 채널 목록에 추가한다. 

conda config --append channels {채널 이름}

 

channel_priority: 채널 우선순위 정하기

기본 환경에서 conda는 default 채널을 사용한다. 

만약 본인이 conda-forge 등 거의 한 채널만 이용한다면 매번 -c 옵션으로 채널을 명시하는 것은 번거로울 수 있다. 

그럴 땐 채널 리스트의 여러 채널들 중에서 우선순위를 정하면 된다. 

conda config --set channel_priority strict

 

--show channels: 채널 우선순위 확인하기

현재 채널의 우선순위는 채널 리스트에서 확인할 수 있다. 

conda config --show channels

가장 위에 있는 것이 가장 우선순위가 높은 채널이다. 

 

pip로 패키지 설치하기

pip install -r {파일 이름}

해당 파일에 명시된 이름과 버전 그대로 패키지를 설치해 준다. 

 

 

이처럼 하나의 가상환경 안에서 pip와 conda를 모두 이용해서 패키지를 설치할 수 있다. 

 

 

 

참고한 포스트

[Anaconda] Conda 명령어, 기본 개념 모음 (tistory.com)

[아나콘다] conda 명령어 목록 (conda command list) (tistory.com)

[Anaconda] conda install 과 pip install 은 똑같은 걸까? (tistory.com)

[기고] 왜 파이썬(Python)인가? (b2en.com)

[Python] pip와 conda의 차이 — vg-rlo (tistory.com)

conda create — conda 4.13.0.post28+5138e307 documentation

Conda channels — conda 4.13.0.post28+5138e307 documentation

Can't execute `conda activate` from bash script · Issue #7980 · conda/conda (github.com)

[Anaconda]가상환경 설치,삭제 (tistory.com)

conda remove — conda 4.13.0.post28+5138e307 documentation

miniconda의 기본 채널 변경 : conda-forge (tistory.com)

 

Git: clone, single-branch, checkout

 

clone

보통 공동으로 작업할 때 깃(git)을 많이 사용하는데, 깃에는 두 개의 저장소 개념이 있다. 

사용자의 PC로컬 저장소, 깃허브 리포지토리원격 저장소라고 한다. 

git clone 명령어를 사용하면 원격 저장소에 저장된 코드를 로컬 저장소로 가져올 수 있다. 

git clone {리포지토리 url(http)}

 

리포지토리 url은 깃 리포지토리 화면에서 code 버튼을 눌러서 얻을 수 있다. 

지금은 http url을 기준으로 리포지토리를 가져오는 방법을 알아보았지만, 나중에는 ssh를 기준으로 리포지토리를 가져오는 방법도 알아봐야겠다. 

 

 

branch

git에는 브랜치(branch)라는 개념이 있다. 하나의 나무에서 여러 개의 가지(branch)가 나온다고 생각하면 편하다.

기본 중심은 master 브랜치이다.

다른 브랜치끼리 서로 합칠 수도 있고, 하나의 브랜치에서 다른 브랜치를 만들어 낼 수도 있다. 

 

여러 개의 브랜치를 만들지 않고 모두가 하나의 브랜치에서 작업한다고 가정해 보자.

깃허브에 작업 내용을 반영할 때, 각자의 코드가 다른 부분이 생기면 그 때마다 충돌이 발생한다.

물론 나중에는 불일치를 해결해야 하겠지만, 깃허브에 코드를 올릴 때마다 이 충돌을 해결하는 것은 번거로울 수 있다. 

 

하지만 브랜치가 있다면 각자의 브랜치에서 작업하고, 나중에 여러 개의 브랜치를 하나로 합칠 때만 이 충돌을 해결해 주면 된다.

따라서 깃허브에 코드를 올릴 때마다 충돌이 발생할 걱정이 없다. 

 

이처럼 브랜치는 하나의 프로젝트를 여러 목적에 따라서 나눌 때(개발용 브랜치, 실제 배포용 브랜치, 테스트용 브랜치 등등), 또는 사용자마다 다른 브랜치를 사용한 다음 하나로 합칠 때도 사용한다. 

 

 

single-branch

위에서 clone으로 깃허브의 코드를 가져올 때, 해당 리포지토리에는 여러 개의 브랜치가 있을 수 있다. 

이때 특정 브랜치의 코드만 가져오고 싶을 때 사용하는 것이 single-branch이다. 

 

즉 single-branch를 사용하면 원격 저장소에서 전체를 다운받는 것이 아니라, 개별 브랜치의 내용만 가져오는 것이 가능하다. 

git clone -b {브랜치 이름} --single-branch {리포지토리 url}

 

 

checkout

single-branch와 달리, 이번에는 리포지토리의 모든 브랜치의 코드를 가져왔다고 해 보자. 

이때 때로는 작업하는 브랜치를 바꿔 가면서 개발해야 하는 상황도 있다. 

checkout을 사용하면 필요할 때마다 현재 작업하는 브랜치를 바꾸면서 작업할 수 있다. 

참고로 checkout의 기본 브랜치는 origin, 즉 master 브랜치이다. 

git checkout {브랜치 이름}

 

'server-side > server' 카테고리의 다른 글

Mac 환경설정  (0) 2024.07.15
Software Release Life Cycle  (0) 2023.07.15
OAuth 2.0 기본원리  (0) 2022.09.26
인증(Authentication)  (0) 2022.07.14
linux: cron 사용해서 자동으로 스케줄 실행하기  (0) 2022.07.09

관리자 페이지에서는 사용자가 정의한 모델에 대한 기본적인 CRUD 기능을 제공한다. 

그러나 때로는 사용자가 직접 원하는 기능을 추가하고 싶을 수 있다. 

이를 위해서 장고에서는 어드민(관리자) 페이지 커스터마이징 기능도 제공한다. 

 

관리자 페이지 커스터마이징 작업은 admin.py 파일에서 이루어진다. 

우선 각 모델에 해당하는 모델 관리자 클래스를 만들어 놓자. 

 

대략적으로 admin.py 에서 정의한 모델 클래스는

 

추가적인 옵션

class ObjectAdmin(매개변수, 여러 개가 들어갈 수도 있다):

    필드들(optional)

    함수들(optional)

 

이렇게 구성된다. 

 

 

admin.ModelAdmin

장고 어드민 인터페이스의 구현체라고 한다. 

정확히 무슨 말인지는 모르겠다!

[이해하면 포스팅하기]

 

 

register

modelAdmin을 등록하기 위해서는 register 선언을 해 주어야 한다. 

admin 파일에 코드를 작성한 뒤, 작성한 내용을 관리자 페이지에 반영하기 위해서 필요한 작업이다. 

작성한 modelAdmin을 register으로 등록하는 방법은 두 가지가 있다. 

 

1. 메소드 사용하기

admin.site.register(모델, 모델 어드민 클래스)

class AuthorAdmin(admin.ModelAdmin):
    // code
    
admin.site.register(Author, AuthorAdmin)

 

2. 데코레이터(decorator) 사용하기

장고에서 @을 사용하여 추가적인 기능을 제공하는 것을 데코레이터(decorator)라고 한다. 

 

@admin.register(모델)

class 모델 어드민 클래스(admin.ModelAdmin):

    // 세부 코드

@admin.register(Author):
class AuthorAdmin(admin.ModelAdmin):
	// code

 

또한 하나의 어드민 클래스에서 여러 모델을 관리할 수도 있기 때문에, 여러 개의 모델을 입력할 수도 있다. 

 

@admin.register(모델1, 모델2, 모델3)

class 모델 어드민 클래스(admin.ModelAdmin):

    // 세부 코드

 

 

관리자 페이지가 다른 어플리케이션과 연결되는 원리

settings.pyINSTALLED_APPS 필드에는 기본값으로 django.contrib.admin이 추가되어 있다. 

이 클래스가 settings.py에 추가되어 있다면, 앱(어플리케이션, 서버)이 시작하자마자 django.contrib.admin 클래스의 모듈은 INSTALLED_APPS 안에 있는, admin을 사용하는 다른 앱에 import 된다. 

 

이게 가능한 이유는 django.contrib.admin의 autodiscover() 함수 때문이다. 

autodiscover() 메소드는서버가 시작하자마자 INSTALLED_APPS에 등록된 다른 앱에서 admin을 사용하는 모델을 찾고, 그 모델들을 관리자 사이트에 등록시킨다. 

 

autodiscover() 메소드는 서버 시작 시 모든 admin에 등록할 모델들을 자동으로 불러오지만, 관리자 페이지를 커스터마이징했을 때 일부 상황에서는 이 기능이 필요하지 않을 수 있다. 

 

autodiscover() 메소드를 사용하고 싶지 않다면, django.contrib.admin 클래스 하위에 있는 apps.SimpleAdminConfig 클래스를 사용해야 한다. 원래 django.contrib.admin은 apps.AdminConfig 메소드를 기본값으로 사용했었다.

 

즉 django.contrib.admin은 아무 옵션도 추가하지 않을 경우 기본값으로 django.contrib.admin.apps.AdminConfig 클래스를 사용해 왔던 것이다. 

그러나 autodiscover() 메소드를 사용하고 싶지 않다면 settings.py의 INSTALLED_APPS에 django.contrib.admin 을 지우고 django.contrib.admin.apps.SimpleAdminConfig를 추가하면 된다. 

 

 

ModelAdmin 인터페이스의 옵션들

ModelAdmin은 규모가 큰 인터페이스이고, 그만큼 커스터마이징을 위한 여러 옵션을 추가할 수 있다. 

옵션은 각 어드민 클래스의 필드 형식으로 지정하면 된다. 

 

1. actions

actions의 값으로는 함수들의 리스트를 입력한다. 

해당 어드민 클래스에서 사용할 수 있는 함수, 기능들을 나열할 수 있다. 

 

2. actions_on_top / actions_on_bottom

True나 False를 입력한다. 

actions 옵션으로 입력한 기능들을 페이지의 위에 표시할지, 아래에 표시할지를 지정한다. 

class ProjectAdmin(admin.ModelAdmin):
	actions_on_top = True

 

3. date_hierarchy

모델의 필드 중 DateField 또는 DateTimeField 타입인 필드 이름을 값으로 갖는다. 

해당 모델의 데이터를 정렬할 때 입력한 필드의 날짜 순서대로 정렬해 준다. 

역순으로 정렬하고 싶다면 필드 이름 앞에 - 을 붙이면 된다. 

class ProjectAdmin(admin.ModelAdmin):
	date_hierarchy = '-register_date'

 

4. empty_value_display

문자열을 값으로 받는다. 

두 가지 방법으로 사용할 수 있다. 

 

첫째로, 각 어드민 클래스의 필드 이름으로 empty_value_display를 사용해서 지정할 수 있다. 

해당 모델의 필드 중 빈 값(null 또는 "" 공백 문자열)이 있다면 그 값을 관리자 페이지에서 어떻게 표시할지를 지정한다. 

class UserAdmin(admin.ModelAdmin):
	empty_value_display = 'EMPTY'

 

둘째로, 데코레이터를 사용해서 각 필드값을 리턴하는 함수 위에 붙여서 사용할 수 있다. 

첫번째 방법에서는 해당 모델에 속한 모든 필드의 빈 값을 같게 나타내지만, 두 번째 방법을 사용하면 각 필드별로 빈 값을 다르게 표시할 수 있다. 

class UserAdmin(admin.ModelAdmin):
	list_display = {'id', 'view_username', 'view_userid'}

	@admin.display(empty_value="no name")
	def view_username(self, obj):
    	return obj.username
        
	@admin.display(empty_value="no id")
	def view_userid(self, obj):
		return obj.userid

 

5. exclude

필드 리스트를 값으로 받는다. 

제외하고 싶은 필드들이 있을 때, exclude의 값으로 입력한다. 

class UserAdmin(admin.ModelAdmin):
	exclude = ['birth-date', 'age']
	// birth-date, age 필드를 제외한 모든 필드가 관리자 페이지에 나타남

 

6. fields

필드 이름 튜플을 값으로 받는다. 

데이터를 수정(change)이나 추가(add)하는 페이지에서 fields의 값에 포함된 필드들만 나타나게 할 수 있다. 

serializer.py에서 read-only로 지정된 필드들만 fields 리스트에 포함될 수 있다. 

더 세부적인 작업을 하고 싶으면 fieldsets 옵션을 사용하자. 

# models.py
class Homework(models.Model):
	title = models.CharField('제목')
	content = models.TextField()
	teacher = models.ChoiceField(choices=TEACHER_LIST)
	submission_date = models.DateTimeField()

# admin.py
class HomeworkAdmin(admin.ModelAdmin):
	fields = ('title', 'content')

 

위 예시의 경우, 데이터를 추가 및 수정하는 페이지에서는 title과 content 필드에 대해서만 수정 및 추가 작업을 할 수 있다. 

또한, fields 튜플 안에서 괄호()를 한번 더 사용하면, fields 튜플 안의 필드들을 한 줄로 나타낼 수 있다. 

 

7. fieldsets

fields와 기본적인 역할은 같고, 튜플을 원소로 갖는 튜플 리스트(two-tuple)를 값으로 받는다. 처음 관리자 페이지에서 보는 카테고리 화면이 아니라, 데이터를 추가나 수정하는 페이지에서 선택한 필드를 그룹으로 묶어서 나타내는 데 사용한다. 

fields 옵션에서는 필드 그룹이 하나만 있었다면, fieldsets 옵션에서는 하나의 모델에 대해서도 여러 필드 그룹을 만들 수 있다. 

여러 개의 그룹을 만들고 싶다면 fieldsets 안에서 튜플을 여러 개 만들면 된다. 각 튜플은 "옵션"과 {} 딕셔너리로 이루어진다. 

 

이런 식으로 만들면 된다. 

 

fieldsets = (

    ("그룹_1의 이름", {

        "fields": ('그룹_1에 들어갈 필드_1', '그룹_1에 들어갈 필드_2')

    }),

    ("그룹_2의 이름", {

        "fields": ('그룹_2에 들어갈 필드_1', '그룹_2에 들어갈 필드_2'), 

    })

)

# models.py
class Course(models.Model):
	student_name = models.CharField()
	lecturer_1 = models.ChoiceField(choices=LECTURER_LIST)
	course_1 = models.ChoiceField(choices=LECTURER_LIST)
	lecturer_2 = models.ChoiceField(choices=LECTURER_LIST)
	course_2 = models.ChoiceField(choices=LECTURER_LIST)
	lecturer_3 = models.ChoiceField(choices=LECTURER_LIST)
	course_3 = models.ChoiceField(choices=LECTURER_LIST)
    
# admin.py
class CourseAdmin(admin.ModelAdmin):
	fieldsets = (
		("강의 1", {"fields": (('lecturer_1', 'course_1'))}),
		// 그룹 이름을 '강의 1'로 설정
		// 강의 1에 해당하는 필드들을 개별 그룹으로 표시
		// 필드들을 한 줄에 표시
        
		("강의 2", {"fields": ('lecturer_2', 'course_2')})
		// 그룹 이름을 '강의 2'로 설정
		// 강의 2에 해당하는 필드들을 개별 그룹으로 표시
		// 각 필드는 한 줄을 차지함
    )

 

또한 fieldsets 내부의 딕셔너리의 값으로 "fields" 뿐만 아니라 다른 값을 추가로 사용할 수도 있다. 

대표적으로는 classes, description 등이 있다. 

 

1) classes

해당 fieldset에 CSS 속성을 적용할 때 사용한다. 

class CourseAdmin(admin.ModelAdmin):
	fieldsets = (
		(None, {
        "fields": (('lecturer_1', 'course_1')),
        "classes": ('wide', 'extrapretty')
        }),
    )

 

2) description

각 fieldset 위에 추가 텍스트를 넣을 때 사용한다. 

 

또한 fields나 fieldsets 옵션을 따로 명시하지 않았다면, 장고에서는 기본값으로 AutoField가 아니고 editable=True로 된 필드들만 관리자 페이지에 포함시킨다. 

 

 

fieldsets, list_display의 차이점

헷갈리는 부분이라 적어보았다. 

fields와 fieldsets는 처음 관리자 페이지에서 모델명을 누르면 나오는 조회 페이지가 아니라, 조회 페이지에서 개별 데이터를 누르면 나오는 추가 및 수정 페이지에서 어떤 필드를 표시할지를 결정한다. 

반면 list_display는 관리자 페이지 시작 화면에서 모델명을 누르면 나오는 조회 페이지에서 어떤 필드를 표시할지를 결정한다. 

 

8. filter_horizontal & filter_vertical

필드 이름 튜플을 값으로 받으며, ManyToManyField(다대다 필드) 에서만 작동한다. 

fieldsets과 마찬가지로 조회 페이지가 아니라 추가 및 수정 페이지에서 작동한다. 

many-to-many field 특성상 선택하는 가짓수가 많을 때는 다루기 어려울 수 있기 때문에, 간단한 인터페이스를 사용해서 데이터를 쉽게 추가 및 수정할 수 있게 했다. 

 

filter_horizontal의 경우 선택되지 않은 가짓수(옵션)이 왼쪽, 선택된 옵션이 오른쪽 박스에 나타난다. 

filter_vertical의 경우 선택되지 않은 옵션이 위쪽, 선택된 옵션이 아래쪽 박스에 나타난다. 

 

9. form

관리자 페이지에서 모델뿐만 아니라 폼 데이터를 추가 및 수정할 때 사용한다. 

# forms.py
class CarForm(forms.ModelForm):
	
    class Meta:
		model = Car
 		exclude = ['engine oil']
        
# admin.py
class CarAdmin(admin.ModelAdmin):
	form = CarForm

 

위의 경우, admin-form-model이 연결되어 데이터를 수정 및 변경할 수 있다. 

 

 

참고한 포스트

Admin actions | Django documentation | Django (djangoproject.com)

The Django admin site | Django documentation | Django (djangoproject.com)

장고 마스터하기 - 5장 - 김땡땡's blog (yonghyunlee.gitlab.io)

 

대부분의 웹 서비스에는 관리자 페이지가 있다. 관리자 페이지에서는 가입한 회원과 관련된 데이터들을 조회할 수 있다. 이를 통해 회사는 서비스가 어떻게 운영되고 있는지도 판단할 수 있기 때문에, 대부분의 웹 서비스에는 관리자 페이지가 있다. 

장고(django)에서도 관리자 페이지 기능을 제공한다. 

 

python manage.py runserver 명령어로 서버를 띄우면 기본 주소인 http://127.0.0.1:8000(포트번호) url로 로컬 서버에 접속할 수 있다. 

 

관리자 페이지를 보려면 http://127.0.0.1:8000/admin url로 접속하면 된다. 

그러면 관리자 페이지를 보기 위해서 관리자 아이디와 비밀번호를 입력하라는 창이 뜬다. 

 

관리자 계정 생성하는 방법

관리자는 보통 다른 사용자(유저)들의 정보를 열람, 수정 및 삭제할 수 있는 권한을 가진다. 따라서 장고에서도 관리자를 user이 아니라 superuser 이라고 부른다. 

 

관리자 계정으로 로그인하려면 우선 관리자 계정을 생성해야 한다. 

python manage.py createsuperuser

 

그러면 이메일, 이메일 주소, Password, Password(again) 을 입력하라는 메시지가 뜬다. 이에 맞게 입력해 주면 된다. 

나중에 관리자 계정으로 로그인할 때는 이메일과 Password를 입력해야 하니 이 두 정보는 꼭 기억하자!

 

Superuser created successfully.

이 메시지가 뜨면 성공적으로 관리자 계정이 만들어진 것이다. 

 

그럼 이제 로그인을 해 보자. 

python manage.py runserver

 

http://127.0.0.1:8000/admin url을 입력하면 로그인 화면이 나온다. 

이메일 에는 앞서 입력한 이메일 정보를, 비밀번호에는 앞서 입력한 Password 정보를 입력하면 로그인이 된다. 

 

그러면 관리자 페이지가 뜨고, 지금까지 프로젝트 내에서 정의한 모델이 있다면 각 모델에 데이터를 추가하거나 변경할 수 있다. 

 

관리자 계정 삭제하는 방법

만약에 관리자 계정의 정보를 잘못 입력하거나 새로운 관리자를 만들고 싶다면 기존 계정을 삭제하면 된다. 

관리자 계정도 결국은 하나의 사용자이기 때문에, 프로그램 내부에서 사용자를 조회하고 superuser인 유저를 삭제하는 방식으로 관리자 계정을 삭제하면 된다. 

 

우선 Shell에 접속한다. 

python manage.py shell

 

Python Shell 에서는 파이썬 문법의 코드를 사용해서 프로젝트의 DB에 저장된 데이터를 조회, 삭제 및 변경할 수 있다. 장고 ORM이 제공하는 기능 중 하나이다. 

파이썬 쉘(shell)이 아니었다면 직접 DB에 들어가서 SQL문으로 데이터를 조회해야 한다. 

 

여기서 확인해야 할 것이 있다. 

보통 관리자 계정은 django.contrib.auth.models.User 의 인스턴스로 저장된다. 

그러나 settings.py 파일의 AUTH_MODELS 필드가 위 클래스가 아닌 다른 클래스로 되어 있다면 관리자 계정이 AUTH_MODELS에 해당하는 클래스의 인스턴스로 저장된다. 

그러므로 settings.py의 AUTH_MODELS 필드가 어떤 클래스로 지정되어 있는지 먼저 확인하자. 

 

내 프로젝트의 경우는 사용자가 직접 만든 account.User 모델로 되어 있었다. 

이 경우, django.contrib.auth.models.User 모델을 import 해서 관리자 계정을 조회하면 다음과 같은 오류가 발생한다. 

즉 관리자를 조회하는 데 사용한 클래스와 AUTH_MODELS 의 클래스가 다를 때 이런 오류가 발생하는 것이다. 

 

User.objects.get(username="", is_superuser=True)

 

AUTH_MODELS 에 입력된 클래스를 import 하고 관리자 계정을 조회해 보자. 

이때 다른 기존의 유저들이 등록되어 있는 상황이라면, 헷갈리지 않기 위해서 is_superuser=True 를 옵션으로 추가한다. 

만약 관리자 계정이 나온다면, 이 계정을 제거해 주면 된다. 

User.objects.get(username="", is_superuser=True).delete()

 

그리고 위의 과정을 통해 다시 관리자 계정을 생성하면 된다. 

 

🗒️ORM이란?

object-relational-mapping 의 약자로, 객체(object)와 관계지향 데이터베이스(relational database)를 연결(mapping)하는 방법이다. 대부분의 프로그래밍 언어(python, java 등)에서는 객체 개념이 있고, 사용자 등 여러 모델을 만들 때 객체를 사용한다. 

하지만 그 모델을 저장할 때는 DB(데이터베이스)에 저장하게 된다. 

ORM은 프로그래밍 언어의 객체 개념을 관계지향 데이터베이스와 연결해 준다. 

 

예를 들어 파이썬으로 프로젝트를 개발하는데 ORM이 없다고 가정해 보자.

그러면 프로젝트에서 유저 등 객체를 생성할 때 DB에 쿼리(query)를 날려야 하고, 파이썬 프로젝트 코드 내부에 직접 유저를 생성하는 SQL 코드를 입력해 줘야 한다. 

그러나 ORM이 있다면 User.objects.create() 등의 간단한 파이썬 문법의 코드로 프로젝트 DB에 유저를 생성할 수 있다. 

 

 

지금까지 장고에서 기본으로 제공하는 관리자 페이지를 보기 위해서 관리자 계정을 생성하고, 조회하는 방법까지 알아보았다. 

그러나 장고는 관리자 페이지에 대해서 더 다양한 기능을 많이 제공하고, 관리자 페이지를 원하는 대로 직접 커스터마이징 할 수도 있다고 한다..! 

다음 번에는 장고의 관리자페이지 커스터마이징 방법에 대해서 작성해 보겠다. 

 

 

참고한 포스트

Writing your first Django app, part 2 | Django documentation | Django (djangoproject.com)

장고(django)에서 superuser를 삭제하는 방법. : 네이버 블로그 (naver.com)

 

+ Recent posts