Django филтър само при агрегат/анотация

Опитвам се да създам доста сложна Django заявка и не напредвам много. Надявах се някой магьосник тук да ми помогне?

Имам следните модели:

class Person(models.Model):
    MALE = "M"
    FEMALE = "F"
    OTHER = "O"
    UNKNOWN = "U"
    GENDER_CHOICES = (
            (MALE, "Male"),
            (FEMALE, "Female"),
            (UNKNOWN, "Other"),
    )


    firstName       = models.CharField(max_length=200, null=True, db_column="firstname")
    lastName        = models.CharField(max_length=200, null=True, db_column="lastname")

    gender          = models.CharField(max_length=1, choices=GENDER_CHOICES, default=UNKNOWN, null=True)
    dateOfBirth     = models.DateField(null=True, db_column="dateofbirth")
    dateInService   = models.DateField(null=True, db_column="dateinservice")
    photo           = models.ImageField(upload_to='person_photos', null=True) 

class SuccessionTerm(models.Model):
    originalName    = models.CharField(max_length=200, null=True, db_column="originalname")
    description     = models.CharField(max_length=200, blank=True, null=True)
    score           = models.IntegerField()

class Succession(model.Model):
    position    = models.ForeignKey(Position, to_field='positionId', db_column="position_id")
    employee    = models.ForeignKey(Employee, to_field='employeeId', db_column="employee_id")
    term        = models.ForeignKey(SuccessionTerm)

class Position(models.Model):
    positionId      = models.CharField(max_length=200, unique=True, db_column="positionid")
    title           = models.CharField(max_length=200, null=True)
    # There cannot be a DB constraint, as that would make it impossible to add the first position.
    dottedLine      = models.ForeignKey("Position", to_field='positionId', related_name="Dotted Line",
                                        null=True, db_constraint=False, db_column="dottedline_id")
    solidLine       = models.ForeignKey("Position", to_field='positionId', related_name="SolidLine", 
                                        null=True, db_constraint=False, db_column="solidline_id")
    grade           = models.ForeignKey(Grade)
    businessUnit    = models.ForeignKey(BusinessUnit, null=True, db_column="businessunit_id")
    functionalArea  = models.ForeignKey(FunctionalArea, db_column="functionalarea_id")
    location        = models.ForeignKey(Location, db_column="location_id")

class Employee(models.Model):
    person                = models.OneToOneField(Person, db_column="person_id")
    fte                   = models.IntegerField(default=100)
    dataSource            = models.ForeignKey(DataSource, db_column="datasource_id")
    talentStatus          = models.ForeignKey(TalentStatus, db_column="talentstatus_id")
    retentionRisk         = models.ForeignKey(RetentionRisk, db_column="retentionrisk_id")
    retentionRiskReason   = models.ForeignKey(RetentionRiskReason, db_column="retentionriskreason_id")
    performanceStatus     = models.ForeignKey(PerformanceStatus, db_column="performancestatus_id")
    potential             = models.ForeignKey(Potential, db_column="potential_id")
    mobility              = models.ForeignKey(Mobility, db_column="mobility_id")
    currency              = models.ForeignKey(Currency, null=True, db_column="currency_id")
    grade                 = models.ForeignKey(Grade, db_column="grade_id")
    position              = models.OneToOneField(Position, to_field='positionId', null=True, 
                                                 blank=True, db_column="position_id")
    employeeId            = models.CharField(max_length=200, unique=True, db_column="employeeid")
    dateInPosition        = models.DateField(null=True, db_column="dateinposition")

Сега, това, което искам, е всеки служител да получи заглавието на длъжността, името на лицето и за всеки срок на приемственост (от които има три) колко пъти позицията на този служител е в таблицата с приемственост и колко пъти всеки от тези служители се среща в таблицата на наследниците. Преди всичко, искам да направя всичко това в една заявка (или по-конкретно, един Django ORM израз), тъй като правя това по страниран начин, но искам да мога да подредя резултата във всеки от тези колони!

Досега имам това:

emps = Employee.objects.all()
       .annotate(ls_st=Count('succession__term'))
       .filter(succession__term__description="ShortTerm")
       .order_by(ls_st)
       .prefetch_related('person', 'position')[lower_limit:upper_limit]

Това е само един от термините за приемственост и бих искал да го разширя до всички термини, като добавя още извиквания за анотиране. Проблемът ми е, че извикването на филтъра работи върху цялата заявка. Бих искал да филтрирам само повикването за преброяване.

Опитах се да направя нещо като Count(succession__term__description'="ShortTerm"), но това не работи. Има ли друг начин да направите това?

Благодаря ви много предварително, Поздрави,

Линус


person Linus    schedule 26.11.2014    source източник


Отговори (1)


И така, това, което искате, е брой на всеки различен тип наследство__срок? Това е доста сложно и не мисля, че можете да направите това с вградения django orm в момента. (освен ако не сте направили .extra() заявка)

В django 1.8 вярвам, че ще можете да го направите с новите изрази за заявки (https://docs.djangoproject.com/en/dev/releases/1.8/#query-expressions). Но, разбира се, 1.8 все още не е пуснат, така че това не ви помага.

Междувременно можете да използвате много удобния пакет django-aggregate-if. (https://github.com/henriquebastos/django-aggregate-if/, https://pypi.python.org/pypi/django-aggregate-if )

С django-aggregate-if вашата заявка може да изглежда така:

emps = Employee.objects.annotate(
        ls_st=Count('succession__term', only=Q(succession__term__description="ShortTerm")),
        ls_lt=Count('succession__term', only=Q(succession__term__description="LongTerm")), # whatever your other term descriptions are.
        ls_ot=Count('succession__term', only=Q(succession__term__description="OtherTerm"))
    )
    .order_by('ls_st')
    .prefetch_related('person', 'position')[lower_limit:upper_limit]

Отказ от отговорност: Никога не съм използвал django-aggregate-if, така че не съм напълно сигурен дали това ще работи, но според README, изглежда, че трябва.

person jproffitt    schedule 26.11.2014