Django - QuerySet上的Admin ListFilter和.extra()

时间:2017-09-06 19:40:13

标签: python django django-queryset

使用.extra()

尝试了解如何在QuerySet上使用Django Admin list_filter超过一天

在AdAdmin中,我需要添加一个新列' ad_hist_status_id'从模型AdHist,所以我可以在SomeListFilter:

上使用这部分代码
def queryset(self, request, queryset):
    return queryset.filter(ad_hist_status_id=self.value())

看起来不可能。使用sql执行此操作非常简单:

select a.*, ah.ad_hist_status_id from ad_ad a
join ad_adhist ah on ah.ad_id = a.id
where
ah.datetime_end is null
order by a.id DESC

到目前为止,我无法在Django Admin中使用这个SomeListFilter,错误是:

FieldError at /admin/ad/ad/

Cannot resolve keyword 'ad_hist_status_id' into field. 
Choices are: addetailscategories, address, adhist, adphotos, 
adprice, adscheduleinfo, age, comment, county, county_id, 
date_inserted, date_updated, description, district, district_id, 
email, id, lat, lng, name, parish, parish_id, schedule_type,
schedule_type_id, telephone, title, user_inserted, user_inserted_id,
user_updated, user_updated_id

我的问题是,如何有效地向QuerySet添加新列,然后如何使用新列查询这个新的QuerySet?

我的代码的某些部分吼叫

模特:

class Ad(models.Model):
    title = models.CharField(max_length=250)
    name = models.CharField(max_length=100)
    description = models.TextField()
    age = models.IntegerField(blank=True, null=True)
    telephone = models.CharField(max_length=25)
    email = models.EmailField()
    district = models.ForeignKey(District)
    county = ChainedForeignKey(County, chained_field="district", chained_model_field="district", sort=True) # smart_selects app
    parish = ChainedForeignKey(Parish, chained_field="county", chained_model_field="county", sort=True) # smart_selects app
    address = models.CharField(max_length=250, null=True, blank=True)
    lat = models.DecimalField(max_digits=9, decimal_places=6, null=True, blank=True)
    lng = models.DecimalField(max_digits=9, decimal_places=6, null=True, blank=True)
    schedule_type = models.ForeignKey(AdScheduleType)
    comment = models.TextField(null=True, blank=True)
    user_inserted = models.ForeignKey(User, null=True, blank=True, related_name='user_inserted_ad')
    date_inserted = models.DateTimeField(auto_now_add=True)
    user_updated = models.ForeignKey(User, null=True, blank=True, related_name='user_updated_ad')
    date_updated = models.DateTimeField(null=True, blank=True)

    def __str__(self):
        return self.name

class AdHist(models.Model):
    ad = models.ForeignKey(Ad)
    datetime_begin = models.DateTimeField()
    datetime_end = models.DateTimeField(null=True, blank=True)
    ad_hist_status = models.ForeignKey(AdHistStatus)
    ad_hist_change_reason = models.ForeignKey(AdHistChangeReason)
    comment = models.TextField(null=True, blank=True)
    user_inserted = models.ForeignKey(User, null=True, blank=True, related_name='user_inserted_ad_hist')
    date_inserted = models.DateTimeField(auto_now_add=True)
    user_updated = models.ForeignKey(User, null=True, blank=True, related_name='user_updated_ad_hist')
    date_updated = models.DateTimeField(null=True, blank=True)

    def __str__(self):
        return self.ad.name

管理员:

class SomeListFilter(admin.SimpleListFilter):
    title = _('Approval State')
    parameter_name = 'ad_hist_status_id'

    def lookups(self, request, model_admin):
        return (
            ('1', _('Approved')),
            ('4', _('Not Approved')),
        )

    def queryset(self, request, queryset):
        return queryset.filter(ad_hist_status_id=self.value())

class AdAdmin(admin.ModelAdmin):
    list_display = ('id', 'name', 'title', 'age', 'telephone', 
                    'email', 'district', 'county', 'parish', 
                    'ad_status', 'ad_hist_change_reason', 'comment',
                    'user_inserted', 'date_inserted', 'user_updated',
                    'date_updated', 'ad_hist_status_id')

    readonly_fields = ('ad_status', 'id', 'ad_hist_change_reason',
                   'ad_hist_status_id')

    list_filter = (SomeListFilter,)

    def get_queryset(self, request):
        qs = super(AdAdmin,self).get_queryset(request).extra(select={'ad_hist_status_id': 'select ad_hist_status_id from ad_adhist where ad_adhist.ad_id = ad_ad.id and ad_adhist.datetime_end is null'},)
        return qs

    def ad_hist_status_id(self, inst):
        return inst.ad_hist_status_id

有人能给我一些线索吗?

最好的问候

2 个答案:

答案 0 :(得分:0)

如果我理解你的问题,你正在寻找:

from django.db.models import F

def queryset(self, request, queryset):
    return queryset.filter(ad_hist_status__id=F('id'))

F expression用于引用同一模型中的字段,要引用相关模型中的字段,您需要使用下划线(__)。

答案 1 :(得分:0)

仔细看看Django field lookups。看看文档说的是什么:

  

基本查找关键字参数采用field__lookuptype=value形式。 (这是双下划线)。

您希望从AdHist获取Ad相关对象,该对象具有相关AdHistStatus,并获取其id

因此,您应该访问此id字段,如:

def ad_hist_status_id(self, instance):
    return instance.adhist.ad_hist_status.id

或者您可以使用双下划线语法直接列出它:

class AdAdmin(admin.ModelAdmin):
    list_display = (..., 'adhist__ad_hist_status__id')