내 사이트에 제시 한 그림을 나타내는 모델이 있습니다. 메인 웹 페이지에서 가장 최근에 방문하지 않은 최신 웹 사이트, 가장 인기있는 웹 사이트 및 임의의 웹 사이트 중 일부를 표시하고 싶습니다.
장고 1.0.2를 사용하고 있습니다.
django 모델을 사용하면 처음 3 개를 쉽게 가져올 수 있지만 마지막 모델 (임의)은 문제가됩니다. 내 견해로는 다음과 같이 코드를 작성할 수 있습니다.
number_of_records = models.Painting.objects.count()
random_index = int(random.random()*number_of_records)+1
random_paint = models.Painting.get(pk = random_index)
그것은 내가보기에 갖고 싶은 것과 같지 않습니다-이것은 전적으로 데이터베이스 추상화의 일부이며 모델에 있어야합니다. 또한 여기서는 제거 된 레코드 (모든 레코드 수가 가능한 모든 키 값을 다루지는 않습니다)와 다른 많은 것들을 처리해야합니다.
다른 옵션은 어떻게 할 수 있습니까? 어떻게 모델 추상화 내부에서 가능합니까?
답변
를 사용 order_by('?')
하면 프로덕션의 두 번째 날에 db 서버가 종료됩니다. 더 좋은 방법은 관계형 데이터베이스에서 임의의 행 가져 오기에 설명 된 것과 같은 것입니다 .
from django.db.models.aggregates import Count
from random import randint
class PaintingManager(models.Manager):
def random(self):
count = self.aggregate(count=Count('id'))['count']
random_index = randint(0, count - 1)
return self.all()[random_index]
답변
답변
order_by ( ‘?’) [: N] 솔루션은 MySQL을 사용하는 경우 중간 크기 테이블에서도 매우 느립니다 (다른 데이터베이스에 대해 알지 못함).
order_by('?')[:N]
SELECT ... FROM ... WHERE ... ORDER BY RAND() LIMIT N
쿼리 로 번역됩니다 .
이는 테이블의 모든 행에 대해 RAND () 함수가 실행 된 후이 함수의 값에 따라 전체 테이블이 정렬 된 다음 첫 번째 N 레코드가 리턴됨을 의미합니다. 테이블이 작 으면 괜찮습니다. 그러나 대부분의 경우 이것은 매우 느린 쿼리입니다.
id에 구멍이있는 경우에도 작동하는 간단한 함수를 작성했습니다 (일부 행이 삭제 된 경우).
def get_random_item(model, max_id=None):
if max_id is None:
max_id = model.objects.aggregate(Max('id')).values()[0]
min_id = math.ceil(max_id*random.random())
return model.objects.filter(id__gte=min_id)[0]
거의 모든 경우에 order_by ( ‘?’)보다 빠릅니다.
답변
간단한 해결책은 다음과 같습니다.
from random import randint
count = Model.objects.count()
random_object = Model.objects.all()[randint(0, count - 1)] #single random object
답변
이런 종류의 작업을 수행하기 위해 모델에 관리자 를 만들 수 있습니다 . 먼저 관리자가 무엇인지 이해하려면 Painting.objects
방법이 포함 된 매니저 all()
, filter()
, get()
자신의 매니저를 생성 등이 – 프리 필터 결과와 결과에 대한 모든 같은 방법뿐만 아니라 자신 만의 방법, 작업을 할 수 있습니다 .
편집 : order_by['?']
방법 을 반영하기 위해 코드를 수정했습니다 . 관리자는 임의의 수의 랜덤 모델을 반환합니다. 이 때문에 단일 모델을 얻는 방법을 보여주는 약간의 사용 코드를 포함 시켰습니다.
from django.db import models
class RandomManager(models.Manager):
def get_query_set(self):
return super(RandomManager, self).get_query_set().order_by('?')
class Painting(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=50)
objects = models.Manager() # The default manager.
randoms = RandomManager() # The random-specific manager.
용법
random_painting = Painting.randoms.all()[0]
마지막으로, 당신은 당신의 모델에 많은 관리자를 가지고, 그래서 만들어 주시기 수 있습니다 LeastViewsManager()
또는 MostPopularManager()
.
답변
다른 답변은 잠재적으로 느리거나 (사용 order_by('?')
) 두 개 이상의 SQL 쿼리를 사용합니다. 다음은 순서가없고 하나의 쿼리 만있는 샘플 솔루션입니다 (Postgres 가정).
Model.objects.raw('''
select * from {0} limit 1
offset floor(random() * (select count(*) from {0}))
'''.format(Model._meta.db_table))[0]
테이블이 비어 있으면 인덱스 오류가 발생합니다. 이를 확인하기 위해 모델에 독립적 인 도우미 함수를 작성하십시오.
답변
내가 어떻게하는지 간단한 아이디어 :
def _get_random_service(self, professional):
services = Service.objects.filter(professional=professional)
i = randint(0, services.count()-1)
return services[i]