[python] Django의 ORM을 사용하여 무작위 레코드를 가져 오는 방법은 무엇입니까?

내 사이트에 제시 한 그림을 나타내는 모델이 있습니다. 메인 웹 페이지에서 가장 최근에 방문하지 않은 최신 웹 사이트, 가장 인기있는 웹 사이트 및 임의의 웹 사이트 중 일부를 표시하고 싶습니다.

장고 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]


답변

간단히 사용하십시오 :

MyModel.objects.order_by('?').first()

QuerySet API에 문서화되어 있습니다.


답변

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]