Заказ по пользовательскому полю модели в django

Я пытаюсь добавить дополнительное настраиваемое поле в модель django. Мне было довольно трудно понять, как сделать следующее, и я буду назначать вознаграждение в размере 150 баллов за первый полностью правильный ответ, когда он станет доступен (после того, как он будет доступен — см. ссылка Улучшение кода представления Python/django).

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

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)
    positions = models.ManyToManyField('Position', through ='PositionTimestamp', blank=True)

    def count(self):
        from django.db import connection
        cursor = connection.cursor()
        cursor.execute(
        """SELECT (
            SELECT COUNT(*)
                FROM videos_video v
                WHERE v.uploaded_by_id = p.id
                OR EXISTS (
                    SELECT NULL
                    FROM videos_videocredit c
                    WHERE c.video_id = v.id
                    AND c.profile_id = p.id
                )
            ) AS Total_credits
            FROM userprofile_userprofile p
            WHERE p.id = %d"""%(int(self.pk))
        )
        return int(cursor.fetchone()[0])

Я хочу иметь возможность упорядочивать по количеству, т.е. UserProfile.objects.order_by('count'). Конечно, я не могу этого сделать, поэтому и задаю этот вопрос.

Раньше я пытался добавить пользовательский диспетчер моделей, но проблема заключалась в том, что мне также нужно иметь возможность фильтровать по различным критериям модели UserProfile: В частности, мне нужно уметь делать: UserProfile.objects.filter(positions=x).order_by('count'). Кроме того, мне нужно оставаться в ORM (не может иметь необработанный вывод sql), и я не хочу помещать логику фильтрации в SQL, потому что существуют различные фильтры, и для этого потребуется несколько операторов.

Как именно я буду это делать? Спасибо.


person David542    schedule 24.07.2011    source источник
comment
не могли бы вы использовать что-то вроде дополнительного модификатора набора запросов? docs.djangoproject.com/en/dev/ref/models/querysets /#дополнительно   -  person niklasdstrom    schedule 24.07.2011
comment
UserProfile.objects.extra(select={'count':SELECT (SELECT COUNT(*) FROM videos_video v WHERE v.uploaded_by_id = p.id ИЛИ СУЩЕСТВУЕТ (SELECT NULL FROM videos_videocredit c WHERE c.video_id = v.id AND c. profile_id = p.id)) AS Total_credits FROM userprofile_userprofile p, где p.id=%d%(...)}). Как мне получить profile.id для каждого, чтобы я мог аннотировать результат для каждого профиля пользователя, а затем заказать по этому счету?   -  person David542    schedule 24.07.2011
comment
ps: вы можете поместить ответ в реальный ответ за награду, даже если это синхронизация для вас.   -  person David542    schedule 24.07.2011


Ответы (3)


"не могли бы вы использовать что-то вроде "дополнительного" модификатора набора запросов?"

см. документы

Сначала я не включил это в ответ, потому что не был уверен, что это действительно сработает или это то, что вам нужно - это было больше похоже на толчок в (надеюсь) правильном направлении.

в документах на этой странице есть пример

запрос

Blog.objects.extra(
    select={
        'entry_count': 'SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id'
    },
)

результирующий sql

SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id) AS entry_count
FROM blog_blog;

Возможно, вы делаете что-то подобное и получаете доступ к идентификатору пользователя, который у вас есть в настоящее время как p.id как appname_userprofile.id

Примечание:

Я просто шучу, так что попробуй немного поиграть. возможно, используйте оболочку для вывода запроса в виде sql и посмотрите, что вы получаете.

person niklasdstrom    schedule 24.07.2011

Моя реакция такова, что вы пытаетесь откусить больше, чем можете прожевать. Разбейте его на кусочки размером с укус, дав себе больше примитивов для работы.

Вы хотите создать эти две части отдельно, чтобы вы могли вызывать их:

  • Получает ли этот пользователь кредит на это видео? вернуть логическое значение
  • За сколько видео этот пользователь получает кредит? вернуться в

Затем используйте комбинацию @property, менеджеров моделей, наборов запросов и методов, которые упрощают выражение того, что вам нужно.

Например, вы можете добавить «кредит» к модели видео, принимающей пользовательский параметр, или к модели пользователя, принимающей параметр видео, или к «менеджеру кредитов» для пользователей, который добавляет количество видео, для которых они имеют кредит.

Это не тривиально, но не должно быть слишком сложно, если вы работаете над этим.

person John Mee    schedule 28.07.2011

модели:

class Positions(models.Model):
    x = models.IntegerField()

    class Meta:
        db_table = 'xtest_positions'

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)
    positions = models.ManyToManyField(Positions)

    class Meta:
        db_table = 'xtest_users'

class Video(models.Model):
    usr = models.ForeignKey(UserProfile)
    views = models.IntegerField()

    class Meta:
        db_table = 'xtest_video'

результат:

test = UserProfile.objects.annotate(video_views=Sum('video__views')).order_by('video_views')
for t in test:
    print t.video_views

документ: https://docs.djangoproject.com/en/dev/topics/db/aggregation/

Либо это то, что вы хотите, либо я совершенно неправильно понял!.. Anywhoo... Надеюсь, это поможет!

person StefanNch    schedule 28.07.2011