1차 업데이트 2020년 4 월 18일
selected , prefetch
class Site(models.Model):
name = models.CharField(max_length=255,)
class Category(models.Model):
name = models.CharField(max_length=255,)
class Article(models.Model):
subject = models.CharField(max_length=255,)
url = models.URLField(unique=True,)
date = models.DateTimeField()
site = models.ForeignKey(Site)
category = models.ManyToManyField(Category)
hit = models.IntegerField(default=0)
위의 클래스는 각각의 테이블이라고 생각하면 된다.
여기에 mysql 에 만약에 연동이 되었다고 가정을 한다면
거기안에 table 명을 지정할 수가 있다 .
class Meta:
table_db = 'articles'
이렇게 짤 수가 있다.
orm 같은경우
python manage.py shell 로 들어가서
from .model improt Article
입력후에
Article.objects. 까지입력을 하고
tab 키를 누르게 되면 기능들이 나오게 된다. 그렇게 할수도 있다.
SQL
select * from test_table;
ORM
Article.objects.all()
SQL
select * from test_table where id =1 ;
ORM
Article.objects.filter(id=1)
만약에 데이터 입력을 누군가에게로 부터 받게하고
그것을 table 에 있는지 확인을 한다고 한다면
만약에 Users 라는 테이블이 있다라는 가정하에 ,
data = json.loads(request.body)
if Users.objects.filter(email = data ['email']).exists():
이렇게 할 수가 있다.
만약에 limit 를 걸어서 그 개수 만큼 가져 오게 하고 싶다면 ?
SQL
select * from test_table limit 10 ;
ORM
Article.objects.all()[:10]
위에 예제는 처음부터 몇까지 가져오는거라면
index 처음 위치를 설정해서 어디까지 정할 수 있는 명령어 이다.
SQL
select * from test_table limit 5,10;
ORM
Article.objects.all()[5:10]
mysql 에서 and 는 예를들어서
User table 에서 성별이 남자이고 , 보유금액이 5500 이상인 사람의 정보를 불러울때
select * from user_table where user_gender = 'male' and user_amount >=5500;
이렇게 적어진다.
SQL
select * from test_table where gender='male' and id > 3;
ORM
>>> Account.objects.filter(id__gt=2)
<QuerySet [<Account: jakdu2>, <Account: jakdu3>, <Account: sory>, <Account: sory2>]>
from django.db.models import Q
>>> Account.objects.filter(Q(name__startswith='jakdu'))
<QuerySet [<Account: jakdu>, <Account: jakdu2>, <Account: jakdu3>]>
>>> Account.objects.filter(id=1,name='jakdu')
<QuerySet [<Account: jakdu>]>
SQL
mysql> select * from Account where name like '%j%';
+----+------------------+--------+--------+--------------------------------------------------------------+----------------------------+----------------------------+
| id | email | name | gender | password | create_at | update_at |
+----+------------------+--------+--------+--------------------------------------------------------------+----------------------------+----------------------------+
| 1 | jakdu@gmail.com | jakdu | male | $2b$12$SM7/J0sJG3AN2R5e6YbBiON3Q596F6tTq2ircli2aAWh/r3r8QCSW | 2020-02-16 04:57:14.224284 | 2020-02-16 04:57:14.224337 |
| 5 | jakdu2@gmail.com | jakdu2 | male | $2b$12$fq.cCKldyXRYtKq7.Zc1XuVhnPJC/Iigq9kTuJFx8tushRj7KIrRi | 2020-02-16 04:59:06.510564 | 2020-02-16 04:59:06.510605 |
| 6 | jakdu3@gmail.com | jakdu3 | male | $2b$12$y/R.eJ52.TWmtZYoYCDsE.jgyw3xUEEOhXxmokmmYMZvO62pBORmu | 2020-02-16 04:59:33.360545 | 2020-02-16 04:59:33.360587 |
+----+------------------+--------+--------+--------------------------------------------------------------+----------------------------+----------------------------+
ORM
>>> Account.objects.filter(name__icontains='j')
<QuerySet [<Account: jakdu>, <Account: jakdu2>, <Account: jakdu3>]>
SQL
mysql> select * from Account where name like 's%';
+----+-----------------+-------+--------+--------------------------------------------------------------+----------------------------+----------------------------+
| id | email | name | gender | password | create_at | update_at |
+----+-----------------+-------+--------+--------------------------------------------------------------+----------------------------+----------------------------+
| 7 | sory@gmail.com | sory | female | $2b$12$DlW.v/s7wzztja9V5Dyq5uyxetn0Jn.0FRu68pqMu9IqFNYmSrmzG | 2020-02-16 05:00:25.514912 | 2020-02-16 05:00:25.514953 |
| 8 | sory2@gmail.com | sory2 | female | $2b$12$Z5zxU2tXgw.ZuPG5l8lwtepo48PoaCQwjpBFNS4TiW8p/Zin.Hc2C | 2020-02-16 05:00:51.773095 | 2020-02-16 05:00:51.773135 |
+----+-----------------+-------+--------+--------------------------------------------------------------+----------------------------+----------------------------+
ORM
>>> Account.objects.filter(name__startswith='s')
<QuerySet [<Account: sory>, <Account: sory2>]>
SQL
mysql> select * from Account where name like '%2';
+----+------------------+--------+--------+--------------------------------------------------------------+----------------------------+----------------------------+
| id | email | name | gender | password | create_at | update_at |
+----+------------------+--------+--------+--------------------------------------------------------------+----------------------------+----------------------------+
| 5 | jakdu2@gmail.com | jakdu2 | male | $2b$12$fq.cCKldyXRYtKq7.Zc1XuVhnPJC/Iigq9kTuJFx8tushRj7KIrRi | 2020-02-16 04:59:06.510564 | 2020-02-16 04:59:06.510605 |
| 8 | sory2@gmail.com | sory2 | female | $2b$12$Z5zxU2tXgw.ZuPG5l8lwtepo48PoaCQwjpBFNS4TiW8p/Zin.Hc2C | 2020-02-16 05:00:51.773095 | 2020-02-16 05:00:51.773135 |
+----+------------------+--------+--------+--------------------------------------------------------------+----------------------------+----------------------------+
ORM
>>> Account.objects.filter(name__endswith='2')
<QuerySet [<Account: jakdu2>, <Account: sory2>]>
SQL
mysql> select * from Account where id >=2;
+----+------------------+--------+--------+--------------------------------------------------------------+----------------------------+----------------------------+
| id | email | name | gender | password | create_at | update_at |
+----+------------------+--------+--------+--------------------------------------------------------------+----------------------------+----------------------------+
| 5 | jakdu2@gmail.com | jakdu2 | male | $2b$12$fq.cCKldyXRYtKq7.Zc1XuVhnPJC/Iigq9kTuJFx8tushRj7KIrRi | 2020-02-16 04:59:06.510564 | 2020-02-16 04:59:06.510605 |
| 6 | jakdu3@gmail.com | jakdu3 | male | $2b$12$y/R.eJ52.TWmtZYoYCDsE.jgyw3xUEEOhXxmokmmYMZvO62pBORmu | 2020-02-16 04:59:33.360545 | 2020-02-16 04:59:33.360587 |
| 7 | sory@gmail.com | sory | female | $2b$12$DlW.v/s7wzztja9V5Dyq5uyxetn0Jn.0FRu68pqMu9IqFNYmSrmzG | 2020-02-16 05:00:25.514912 | 2020-02-16 05:00:25.514953 |
| 8 | sory2@gmail.com | sory2 | female | $2b$12$Z5zxU2tXgw.ZuPG5l8lwtepo48PoaCQwjpBFNS4TiW8p/Zin.Hc2C | 2020-02-16 05:00:51.773095 | 2020-02-16 05:00:51.773135 |
+----+------------------+--------+--------+--------------------------------------------------------------+----------------------------+----------------------------+
ORM
>>> Account.objects.filter(id__gte=2)
<QuerySet [<Account: jakdu2>, <Account: jakdu3>, <Account: sory>, <Account: sory2>, <Account: sory3>]>
SQL
mysql> select * from account where id <=2;
+----+-----------------+-------+--------+--------------------------------------------------------------+----------------------------+----------------------------+
| id | email | name | gender | password | create_at | update_at |
+----+-----------------+-------+--------+--------------------------------------------------------------+----------------------------+----------------------------+
| 1 | jakdu@gmail.com | jakdu | male | $2b$12$SM7/J0sJG3AN2R5e6YbBiON3Q596F6tTq2ircli2aAWh/r3r8QCSW | 2020-02-16 04:57:14.224284 | 2020-02-16 04:57:14.224337 |
+----+-----------------+-------+--------+--------------------------------------------------------------+----------------------------+----------------------------+
ORM
>>> Account.objects.filter(id__lte=2)
<QuerySet [<Account: jakdu>]>
SQL
select * from account where id > 2 ;
select * from account where id < 2 ;
2 보다 큰것이 출력 되고
밑에는 2보다 작은것이 출력됨
ORM
>>> Account.objects.filter(id__gt=2)
<QuerySet [<Account: jakdu2>, <Account: jakdu3>, <Account: sory>, <Account: sory2>, <Account: sory3>]>
>>> Account.objects.filter(id__lt=2)
<QuerySet [<Account: jakdu>]>
SQL
insert into account set name='monster';
ORM
account = Account(name='monster')
account.save()
ORM
account = Account.objects.get_or_create(name='monster1')
# save 메서드 호출 없이도 바로 입력됨
참고자료
https://blog.naver.com/dudwo567890/220924729927
https://docs.djangoproject.com/en/1.10/topics/db/queries/
순서대로 뿌려주고 싶을때가 있다 . 보통 order_by 를 지정하지 않는다면 ,
id 순서대로 뿌려주게 되어있습니다.
Product.objects.all().order_by('name').values('price')
이름 순서대로 뿌려주는데 값을 price 만 보여달라는 orm 입니다.
그런데
Product.objects.select_related('harvest_year' , 'measure').order_by('name').values('price')
이렇게 해도 똑같은 결과가 나오게 된다 .
왜지 ??
select_related 를 무엇을 쓰기위해서 저렇게 하는걸까 ??
select_related 는 내가 참조하는것에 대한 데이터를 가져올때 사용한다.
위와 똑같이
Product.objects.select_related('harvest_year' , 'measure').order_by('name').values('harvest_year_id__year')
입력을 해주면
<QuerySet [{'harvest_year_id__year': '2014'}, {'harvest_year_id__year': '2016'},
{'harvest_year_id__year': '2014'}, {'harvest_year_id__year': '2015'},
{'harvest_year_id__year': '2015'}, {'harvest_year_id__year': '2016'},
{'harvest_year_id__year': '2016'}, {'harvest_year_id__year': '2015'},
{'harvest_year_id__year': '2016'}, {'harvest_year_id__year': '2015'},
{'harvest_year_id__year': '2015'}, {'harvest_year_id__year': '2015'},
{'harvest_year_id__year': '2015'}, {'harvest_year_id__year': '2016'},
{'harvest_year_id__year': '2016'}, {'harvest_year_id__year': '2016'},
{'harvest_year_id__year': '2015'}, {'harvest_year_id__year': '2016'},
{'harvest_year_id__year': '2015'}, {'harvest_year_id__year': '2014'},
'...(remaining elements truncated)...']>
이러한 결과값이 나오게되지만
harvest_year = models.ForeignKey('HarvestYear', on_delete = models.SET_NULL, null = True)
변수를 선언한 곳을 보면 이렇게 되어있다.
참조를 하게되면
harvest_year 뒤에 자동적으로 harvest_year_id 라고 생성이 되기때문입니다.
values('harvest_year_id__year')
를 해주면 참조하고 있는 harvest_year 에 있는 year 에 대한 값을 가져오게 됩니다.
In [21]: Product.objects.select_related('harvest_year').order_by('name').get(id=1).harvest_year
Out[21]: <HarvestYear: HarvestYear object (1)>
이렇게 적을 수도 있는데 ,
Product 테이블에 있는 데이터 중에 id 값이 1 것중에 참고하고있는 harvest 객체를 가져오게 됩니다.
In [22]: Product.objects.select_related('harvest_year').order_by('name').get(id=1).harvest_year.year
Out[22]: '2014'
객체 중에 필드 하나를 입력하면 필드값을 출력해줍니다.
In [30]: Product.objects.select_related('harvest_year').order_by('id').values('id')[1:10]
Out[30]: <QuerySet [{'id': 2}, {'id': 3}, {'id': 4}, {'id': 5}, {'id': 6}, {'id': 7}, {'id': 8}, {'id': 9}, {'id': 10}]>
그리고 마지막에 [ ] 를 해주면 몇개를 출력할 것인지 정할 수가 있습니다.
prefetch_related 를 사용하는 경우는 크게 두가지입니다.
many to many 의경우 중간테이블에서 관리하게 됩니다.
디비에 들어가서 table 를 보게되면 칼럼이 생기지 않은 것을 볼수 있습니다.
테이블이 이렇게 되어있다고 가정을 하겠습니다.
category 테이블에는 ,
<QuerySet [{'id': 1, 'name': 'Fresh', 'image_url': 'http://cdn.shopify.com/s/files/1/1148/3974/collections/collection_02_fresh_large.png?v=1455202997', 'description': 'You’ll find here a lot of delightful vegtables & fruits that were harvested and are waiting to serve you'},
{'id': 2, 'name': 'Frozen', 'image_url': 'https://cdn.shopify.com/s/files/1/1148/3974/collections/collection_03_frozen_large.png?v=1455263893', 'description': 'Look through fruits & vegetables that are saved for later due to the'},
{'id': 3, 'name': 'Dried', 'image_url': 'https://cdn.shopify.com/s/files/1/1148/3974/collections/collection_04_dried_large.png?v=1455263955', 'description': 'We transform herbs, fruits & vegetables from fresh to'},
{'id': 4, 'name': 'Liquid', 'image_url': 'https://cdn.shopify.com/s/files/1/1148/3974/collections/collection_05_liquid_large.png?v=1455263995', 'description': 'Almost every cooking requires some oil or sauses in the kitchen. We got you covered here with specially crafted'},
{'id': 5, 'name': 'sale', 'image_url': 'https://cdn.shopify.com/s/files/1/1148/3974/collections/collection_06_sale_large.png?v=1456211951', 'description': None},
{'id': 6, 'name': 'Specials', 'image_url': None, 'description': None},
{'id': 7, 'name': 'Cooked', 'image_url': None, 'description': None}]>
이렇게 들어가 있습니다.
이것을 Product 테이블에서 접근할때는 prefetch_related 를 사용해야합니다.
Product.objects.prefetch_related('category').filter(category__name='Fresh')
위처럼 입력하면 밑에와 같은 결과가 나옵니다.
In [78]:
Out[78]: <QuerySet [<Product: Product object (5)>,
<Product: Product object (8)>,
<Product: Product object (10)>,
<Product: Product object (11)>,
<Product: Product object (12)>,
<Product: Product object (13)>,
<Product: Product object (14)>,
<Product: Product object (16)>,
<Product: Product object (17)>,
<Product: Product object (19)>,
<Product: Product object (20)>,
<Product: Product object (21)>,
<Product: Product object (22)>,
<Product: Product object (23)>,
<Product: Product object (25)>,
<Product: Product object (27)>,
<Product: Product object (31)>,
<Product: Product object (33)>,
<Product: Product object (35)>,
<Product: Product object (41)>,
'...(remaining elements truncated)...']>
그리고 ,
Product.objects.prefetch_related('category').filter(category__name='Frozen')
라고 입력하면
밑에와 같이 결과가 나오게 됩니다.
왜 이것은 하나가 나왔을까요 ??
Out[76]: <QuerySet [<Product: Product object (44)>]>
하나밖에 없으니깐요..
이런식으로 ManytoMany 를 들고오시면 됩니다.
역참조는 그러니깐 내가 바라보는것이 아니라
바라보는것을 당하는것이다. ㅡㅡ;; 말이 이상한데
내가 바라보는것이 아니라 , 어떤것이 나를 바라보는것 ?? 이라고 생각하시면 될것 같습니다.
class Product(models.Model):
...
bundle = models.ManyToManyField('Bundle', through = 'ProductBundle')
class Bundle(models.Model):
title = models.CharField(max_length = 100)
price = models.CharField(max_length = 50, null = True)
is_in_promotion = models.BooleanField(default = False)
Bundle.objects.prefetch_related('product_set').get(id=1)
역참조를 할땐 뒤에 _set 을 넣어주면 됩니다.
나를 바로보고있는것 _set
여기서는 product 테이블이 bundle 테이블을 바라보고있네요 .
Out[97]: <Bundle: Bundle object (1)>
결과는 이렇게 나옵니다. 왜 ?? id = 1 만을 들고왔으니깐요
Bundle.objects.prefetch_related('product_set').get(id=1).product_set.values('name')
자 그럼 이렇게 입력을 하면 어떻게 되는걸까요 ?
get(id=1) 까지하면 그 객체 하나만 들고오는데 ,
그 레코드
에서 그 레코드를 바라보고있는 Product 테이블의 레코드를 가져오게 됩니다.
무엇을 ?? name 만 가져오게 되죠 .
recipe_info = (Recipe
.objects
.order_by('id')
.values('id',
'title',
'description',
'company',
'thumbnail_url',
'posting_date'
)[offset:offset + limit])
이렇게 되어있지 않고 만약에
Recipe.objects.order_by('id).values('id)~~~~
이렇게 되어있다면
( ) 이것으로 감싸줘서 코드정렬을 하면됩니다.
엇?? 그러면 튜플로 나오지 않나 ??
라고 생각하실수도 있습니다.
하지만 나중에 JsonResponse 로 뿌려주게 될때 , list 로변환시키면 됩니다.
class Meta:
managed = False
db_table = 'companys'
보통 managed 는 default 가 true 이다.
https://docs.djangoproject.com/en/3.1/ref/models/options/
기존 구축된 디비가 있거나 디비를 따로 구축한다면,
장고에서 매니지는 안하고 orm 정도만 사용하는 경우에 사용하게 된다.