Как я могу эффективно выбирать случайные записи в Django, когда каждая запись использует UUID, а не последовательные идентификаторы? - PullRequest
0 голосов
/ 27 апреля 2020

У меня есть несколько моделей постов, где ID - это UUID. Теперь я хочу отобразить несколько случайных предложений постов, которые пользователь также хотел бы видеть в моем шаблоне post_detail ...

Вот так я обрабатываю предложения постов, которые пользователь также может видеть в views.py:

def post_proposals():
    post_elements = sorted(
        chain(
            Model1.objects.all(),
            Model2.objects.all(),
            Model3.objects.all()
        )
    )
    post_elements_list = list(post_elements) # Conversion to list is requierd by random
    post_proposals = random.sample(post_elements_list)
    return post_proposals


def post_detail(request, pk):
    ...
  args = {
    'post': post,
    'post_proposals': post_proposals(),
  ...

template. html:

 {% for post_proposal in post_proposals %}
    <h1>{{ post_proposal.title }}</h1>
 {% endfor %}

Проблема сейчас в том, что это снизит производительность моей базы данных из моего понимания ... Как только у меня будет храниться много постов в моей базе данных запрос станет массовым. Сначала я должен получить все элементы 3 моделей, а затем получать 10 случайных записей из списка каждый раз, когда сообщение отображается для пользователя.

Я также обнаружил следующее, что представляется весьма полезным:

https://elpenia.wordpress.com/2010/05/11/getting-random-objects-from-a-queryset-in-django/

К сожалению, я не могу использовать это решение, так как работаю с UUID, которые являются непоследовательными строками, а не значениями int, которые у меня были бы с идентификаторами.

Ответы [ 2 ]

2 голосов
/ 27 апреля 2020

Проблема в том, что у вас разные модели, что делает операцию очень дорогой. Я бы предложил вам добавить новую модель, в которой все модели, которые вы хотите запросить, зарегистрированы как внешние ключи или пара id / type. При этом вы можете обойти недостаток дизайна и либо

  1. извлекать только идентификаторы: model.objects.all (). Values_list ('id', flat = True). результат random.sample будет идентификатором, и вы можете извлекать сообщения, используя идентификатор напрямую

  2. , генерировать случайный диапазон между 1 и count () новой таблицы, а затем вытягивать фактические сообщения путем обработки записей с соответствующим индексом. Это потребует от вас добавления индексного поля, поскольку идентификаторы могут быть не последовательными (удаление и прочее)

, как только вы получите идентификаторы, вы можете получить набор с помощью model.objects.filter ( id__in = post_proposals) и обработать его далее

--- РЕДАКТИРОВАТЬ образец реализации ---

модель, которая обхватывает другие модели, будет выглядеть примерно так:

class Model1(models.Model):
   @staticmethod
   def get_ref_type(): return 0

   def create(self):
      super(Model1,self).create()
      Posts.register(self,Model1.get_ref_type())

   def delete(self):
      Posts.un_register(self,Model1.get_ref_type())
      super(Model1,self).delete()

class Posts(models.Model):
  class Meta: 
    ....

  #sequential index, this is what you will filter against
  index    = models.IntegerField(default=0)
  #type of the model you want to query
  ref_type = models.IntegerField(default =-1)
  #id of the record in the table defined in the ref_type field
  ref_id   = models.IntegerField(default =-1)

  @staticmethod
  def register(f_objRecord,f_intType):
      l_objWrp = Posts()
      #a separate table that will be used to hold the free indexes
      #it will ensure that even when you delete records, there
      #won't be any holes in the set
      l_objWrp.index = PostIndex.get_index()
      l_objWrp.ref_id = f_objRecord.id 
      l_objWrp.ref_type = f_intType

      l_objWrp.save()

  @staticmethod
  def un_register(f_objRecord,f_intType):
     l_objWrp = Posts.objects.get(ref_type=f_intType,ref_id=f_objRecord.id)
     PostIndex.free_index(l_objWrp.index)
     l_objWrp.delete()
  def get_data(self):
     l_intRefType = self.ref_type
     l_intId      = self.ref_id

     l_objRecord = None
     if l_intRefType == Model1.get_ref_type():
        l_objRecord = Model1.objects.get(id=l_intId)
     elif l_intRefType == Model2.get_ref_type():
       .....

     if l_objRecord: 
        #pull the data you want
     else: raise('unknown model type')
0 голосов
/ 27 апреля 2020

Вы можете попытаться заставить базу данных упорядочить случайным образом, а затем нарезать, например,

Model1.objects.order_by('?')[:3]`.

Документы order_by предупреждают, что это может быть дорого и медленно, но может стоит проверить, дает ли он приемлемые результаты на практике.

...