[ summary ]
- 멜론 song_search로 Django 복습
- Django_document : Making queries
[ 과제 ]
- field lookups : 필드에 대해서 조건을 걸 수 있는 것
- 멜론 songs 과제
- 오늘 배운거 문서로 정리할 것
Making queries
# weblog.models.py
from django.db import models
from django.db import models
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def __str__(self):
return self.name
class Author(models.Model):
name = models.CharField(max_length=200)
email = models.EmailField()
def __str__(self):
return self.name
class Entry(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
headline = models.CharField(max_length=255)
body_text = models.TextField(blank=True)
pub_date = models.DateField(blank=True, null=True)
mod_date = models.DateField(auto_now = True)
authors = models.ManyToManyField(Author,blank=True)
n_comments = models.IntegerField(default=0)
n_pingbacks = models.IntegerField(default=0)
rating = models.IntegerField(default=0)
def __str__(self):
return self.headline
Create objects
models.py
에 있는class
는 데이터베이스의 테이블을 의미한다. 그리고 각 클래스의 인스턴스들은 데이터베이스 테이블의 레코드를 의미save()
를 이용하여 데이터베이스에 저장, 이 전까지는 데이터베이스에 접근하지 않음save()
호출 후, INSERT SQL 문이 실행
# 메모리상에만 b라는 인스턴스가 만들어진 것
b = Blog(name='BEatles Blog', tagline = 'ALl the latest Beatles news')
# 데이터베이스에 저장
b.save()
Saving change to objects
# 속성을 변경한후 save() 하면, UPDATE SQL 명령문이 실행
b.name = 'New name'
b.save()
Saving ForeignKey and ManyToManyField
- ManyToManyField의 경우,
add()
를 사용해서, 레코드를 추가
joe = Author.objects.create(name ='Joe')
entry.author.add(joe)
# 여러명을 할때 이런식으로
paul, george, ringo = [Author.objects.create(name = name) for name in ['Paul','George','Ringo']]
entry.authors.add(john, paul, george, ringo)
Retrieving objects(객체 검색하기)
- 검색과 관련된 SQL 용어는 SELECT, 그리고 WHERE 또는 LIMIT 가 있다.
- 쿼리셋은 모델의 Manager 을 통해 사용할 수 있다.
- 각 모델은 하나의 매니저들을 가지고 있고, objects 라는 기본 매니저가 있다.
Retrieving all objects
# 전체 가져오기
Entry.objects.all()
Retrieving specific objects with filters
- filter
- exclude =
WHERE NOT
from datetime import date
Entry.objects.create(blog = b, headline ='test', pub_date = date(2006,01,01))
# 같은 결과
Entry.objects.filter(pub_date__year=2006)
Entry.objects.all().filter(pub_date__year=2006)
Chaining filters
- 여러개 겹쳐서
filter
을 할 수 있다.
# 오류 났음 왜 났는지 질문
In [15]: Entry.objects.filter(headline__startwith = 'What')
-----------------------------------------------------------------------
FieldError: Unsupported lookup 'startwith' for CharFiel
Filtered QuerySets are unique
# q1을 가지고 q2,q3 쿼리셋이 만들어지지만, q1에는 영향이 없다.
q1 = Entry.objects.filter(headline__startswith="What")
q2 = q1.exclude(pub_date__gte=datetime.date.today())
q3 = q1.filter(pub_date__gte=datetime.date.today())
QuerySet are lazy
쿼리셋이 평가 될 때까지 실행되지않음 쿼리셋실행 관련 자료
Retrieving a single object with get()
- get : Does not exist
- filter : 빈 쿼리셋 생성
get()
은 반드시 한개하고만 연결되야 한다. 한개 이상인 경우 오류
Limiting querysets
- 슬라이스 한 연산에는
ordering
이 불가
# 이 경우에는 그냥 쿼리셋만 만드는 것
q = Entry.objects.all()[5:10]
# step을 사용했을 경우에면 쿼리문이 평가가 된다. (실행)
# 평가가 되고 난 후에 리스트로 반환
q = Entry.objects.all()[5:10:2]
Field lookups
- SQL WHERE
- exact / iexact / contains
Lookups that span relationships
- 정방향, 역방향 참조 관련 내용
- 관련 모델이 없는 경우, 오류가 발생하지 않는다. 그래서 NULL 이 있을 경우 오류가 나게 하려면
__isnull = False
# 역방향 entry -> authors -> name
Blog.objects.filter(entry__authors__name='Lennon')
Spanning multi-valued relationships
1.headline ‘Lennon’이 있고, 2008년에 출판된 Entry 두 조건 만족하는 blog e1 = Entry(headline = Lennon, pub_date = 2008)
2.headline에 ‘Lennon’이 있는 Entry와 2008년에 출판된 Entry가 있는 blog e2 = Entry(headline=’lhy’, pub_date=2008) e3 = Entry(headline=’Lennon’,pub_date=2000)
# 1번의 경우
# 같은 entry에 조건이 걸리는 경우
Blog.objects.filter(entry__headline__contains='Lennon',entry__pub_date__year=2008)
# 2번 조건의 경우
# filter가 실행된 값에서 Blog에서 두번째 조건을 건다.
# entry가 다중 상속인 경우, and 조건이 아니라,
# 첫번째 Filter 에서 나온 결과값에서 다시 한번 filter 를 적용
Blog.objects.filter(entry__headline__contains='Lennon').filter(entry__pub_date__year=2008)
# exclude 의 경우는 filter처럼 작동하지 않는다.
# 조건 두개가 각각 만족되는 경우 삭제
Blog.objects.exclude(
entry__headline__contains='Lennon',
entry__pub_date__year=2008,
)
# 한번에 두 조건 모두를 만족 시키는 것을 삭제
Blog.objects.exclude(
entry__in=Entry.objects.filter(
headline__contains='Lennon',
pub_date__year=2008,
),
)
Filters can reference fields on the model
- 쿼리셋이 실행된 후에는 변경된 데이터를 가져오지 못하므로, 변경되면 다시한번 실행시켜줘야 한다.
- F = 동일한 모델 인스턴스에서 다른 필드를 비교 할때 사용
Caching and QuerySets
- 한번 평가된 쿼리셋은 데이터베이스에서 정보를 가져온다. 이후에 같은 쿼리셋이 평가되는 경우엔, 데이터베이스에서 다시 가져오는 것이 아닌 이전에 저장된 정보를 사용한다.
- 그렇기 때문에 새로운 정보가 업데이트 될때마다 이를 반영되는게 어렵다.
# 예상된 결과값이 다른 것을 방지하기 위해선 아래와 같은 방법 사용
queryset = Entry.objects.all()
print([p.headline for p in queryset]) # Evaluate the query set.
print([p.pub_date for p in queryset]) # Re-use the cache from the evaluation.
# 쿼리셋을 일부분만 할 경우, 데이터베이스를 다녀오긴 하나 데이터를 가지고 있지 않는다'
queryset = Entry.objects.all()
print(queryset[5]) # Queries the database
print(queryset[5]) # Queries the database again
Complex lookups with Q objects
- Q = OR 문을 사용했을 때
- 조건만 만들 수 있다.
# INVALID QUERY
# 키워드 인자는 위치인자보다 항상 뒤에 와야 하기 때문에 오류!
Poll.objects.get(
question__startswith='Who',
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)
Comparing objects
각 속성들 비교할 때는 PK
비교를 하는게 가장 중요하다.
Deleting objects
CASCADE
로 걸려있는 경우에는 delete 메소드가 실행되지 않을 수도 있다.
사용자가 delete재정의할 경우, 그 메소드가 실행되지 않을 수도 있다.
이것을 실행시키기 위해선 수동으로 실행시켜야한다
Copying model instances
# copy
blog = Blog(name='My blog', tagline='Blogging is easy')
blog.save() # blog.pk == 1
blog.pk = None
blog.save() # blog.pk == 2
그러나 many_to_many의 경우, MTM은 그대로이기 때문에 복사 불가
one_to_one도 A-B,A-C 이런식이 되면 A가 어떤걸 선택해야 할지 모르기 때문에, 1:1 조건에 맞게끔 해야한다.
Updating multiple objects at once
update()
의 경우, 데이터베이스에 바로 적용이 되고, 결과값으로 업데이트된 갯수들이 반환됨.- 데이터베이스에 적용이 바로 되기 때문에,
save()
를 하지 않아도 됨 - Signals : 중복되는 일이 여러 모델에서 사용될 때 signals로 알리는 것 ex) entry 가 만들어질때마다 구독자에게 이메일이 전송 됨. 모델 50개가 되어야 하고 save가 50개 필요 그래서 이메일을 보내야한다는 Signals 로
- 자기자신의 테이블에서만 사용가능
postgreSQL
<!-- INSTALL -->
sudo apt-get update
sudo apt-get install postgresql postgresql-contrib
<!-- USER MAKE -->
sudo -u postgres createuser --interactive
Enter name of role to add: kahee
Shall the new role be a superuser? (y/n) y
<!-- P: password s: superuser -->
~ sudo -u postgres createuser -P -s kahee
Enter password for new role:
Enter it again:
<!-- 사용자 확인 -->
psql postgreSQL
\du
List of roles
Role name | Attributes | Member of
-----------+------------------------------------------------------------+-----------
kahee | Superuser, Create role, Create DB | {}
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
ykh | Superuser, Create role, Create DB | {}
<!-- 데이터베이스 생성 -->
sudo -u postgres createdb fc-django-document --owner=kahee
기존 데이터 백업하기
git에 업로드 되지 않도록 주의
<!-- dump.json파일로 백업 -->
./manage.py dumpdata weblog auth --indent=4 > dump.json
postgresSQL을 Django에서 사용하기 위해서 설정
# config/seetings.py
# Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'fc-django-document',
'USER': 'kahee',
'PASSWORD' : '설정된 암호 입력',
'HOST': 'localhost',
'PORT': '5432',
}
}
설정이 끝나면 makemigrations
실행하면 아래와 같은 오류가 발생
이는 postgres와 python을 연결해주는 라이브러리 psycopg2
가 없어서 발생된다.
그래서 설치 후, makemigrations
하면 해결!
jango.core.exceptions.ImproperlyConfigured: Error loading psycopg2 module: No module named 'psycopg2'
pip install psycopg2
./manage.py makemigrations
./manage.py migrate
<!-- 백업파일적용 -->
<!-- 그러나 나의 경우, 오류가 생겨서 백업이 제대로 안됬음 ㅜㅠ -->
./manage.py loaddata dump.json