Django queryset没有返回不同的值

时间:2016-06-02 12:51:26

标签: django sqlite django-queryset

我有一个查询,由于某种原因没有返回不同的值,即使我已经指定了distinct,我认为这可能是因为唯一,所以我删除了,但列表仍然是相同的

circuit_providers =  CircuitInfoData.objects.only('provider').values('provider').distinct()

我只想要一份unqiue提供者列表

model.py

from __future__ import unicode_literals
from django.db import models
import string
import random
import time
import os

# Create your models here.
from service.models import ServiceContacts

def site_photos_path(instance, filename):
    file ,extension = os.path.splitext(filename)
    # file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
    chars=string.ascii_uppercase + string.digits
    random_string = ''.join(random.choice(chars) for _ in range(6))
    filename = '%s-%s%s' % (random_string,time.strftime("%d-%m-%H-%M-%S"),extension)
    return 'site_photos/{0}'.format(filename)

def service_upload_path(instance, filename):
    file ,extension = os.path.splitext(filename)
    # file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
    chars=string.ascii_uppercase + string.digits
    random_string = ''.join(random.choice(chars) for _ in range(6))
    filename = '%s-%s%s' % (random_string,time.strftime("%d-%m-%H-%M-%S"),extension)
    return 'service_files/{0}'.format(filename)    

def site_files_path(instance, filename):
    file ,extension = os.path.splitext(filename)
    # file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
    chars=string.ascii_uppercase + string.digits
    random_string = ''.join(random.choice(chars) for _ in range(6))
    filename = '%s-%s%s' % (random_string,time.strftime("%d-%m-%H-%M-%S"),extension)
    return 'site_files/{0}'.format(filename)   

provider_choices = (
        ('KCOM','KCOM'),
        ('BT','BT'),
        ('EE','EE'),
        ('THREE','THREE'),
    ) 
circuit_choices = (
        ('DSL','DSL'),
        ('VDSL','VDSL'),
        ('MPLS','MPLS'),
        ('4G','4G'),
        ('Internet Leased Line','Internet Leased Line'),
    )     

subnet_mask_choices = (
        ('/16','/16'),
        ('/24','/24'),
        ('/25','/25'),
        ('/26','/26'),
        ('/27','/27'),
        ('/28','/28'),
        ('/29','/29'),
        ('/30','/30'),
        ('/31','/31'),
    )       

class ShowroomConfigData(models.Model):
    location = models.CharField(max_length=50)
    subnet = models.GenericIPAddressField(protocol='IPv4')
    r1_loopback_ip = models.GenericIPAddressField(protocol='IPv4',verbose_name="R1 Loopback IP")
    r2_loopback_ip = models.GenericIPAddressField(protocol='IPv4',verbose_name="R2 Loopback IP")  
    opening_date = models.DateField(verbose_name="Showroom opening date")
    last_hw_refresh_date = models.DateField(verbose_name="Date of latest hardware refresh")
    is_showroom = models.BooleanField(default=True,verbose_name="Is this site a showroom?")

    class Meta:
            verbose_name = "Showroom Data"
            verbose_name_plural = "Showroom Data"  
            ordering = ('location',)

    def __unicode__(self):
        return self.location   


class MajorSiteInfoData(models.Model):
    location = models.CharField(max_length=200)
    major_subnet = models.GenericIPAddressField(protocol='IPv4',verbose_name="Major Site Subnet")
    routed_subnet = models.GenericIPAddressField(protocol='IPv4',verbose_name="Routed Link Subnet")
    bgp_as = models.CharField(max_length=6,verbose_name="BGP AS Number")

    class Meta:
            verbose_name = "Major Site Data"
            verbose_name_plural = "Major Site Data"      

    def __unicode__(self):
        return self.location

class CircuitInfoData(models.Model):    
    showroom_config_data = models.ForeignKey(ShowroomConfigData,verbose_name="Install Showroom")
    major_site_info = models.ForeignKey(MajorSiteInfoData,verbose_name="Install Site") 
    circuit_type = models.CharField(max_length=100,choices=circuit_choices)    
    circuit_speed = models.IntegerField(blank=True)
    circuit_bearer = models.IntegerField(blank=True)
    provider = models.CharField(max_length=200,choices=provider_choices)
    ref_no = models.CharField(max_length=200,verbose_name="Reference No")

    class Meta:
        verbose_name = "Circuit Data"
        verbose_name_plural = "Circuit Data"
        ordering = ('showroom_config_data__location','circuit_speed')

    def __unicode__(self):
        return '%s | %s | %s | %s | %s' % (self.showroom_config_data.location,self.major_site_info.location, self.provider, self.service_type, self.ref_no)

来自下面的shell

[root@network-tools infternal]# python manage.py shell
Python 2.7.5 (default, Nov 20 2015, 02:00:19)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from networks.models import CircuitInfoData
>>> d = CircuitInfoData.objects.values('provider').distinct()
>>> for item in d:
...  print item
...
{'provider': u'BT'}
{'provider': u'BT'}
{'provider': u'KCOM'}
{'provider': u'BT'}
{'provider': u'BT'}
{'provider': u'KCOM'}
.....
>>> print d.query
SELECT DISTINCT "networks_circuitinfodata"."provider", "networks_showroomconfigdata"."location", "networks_circuitinfodata"."circuit_speed" FROM "networks_circuitinfodata" INNER JOIN "networks_showroomconfigdata" ON ("networks_circuitinfodata"."showroom_config_data_id" = "networks_showroomconfigdata"."id") ORDER BY "networks_showroomconfigdata"."location" ASC, "networks_circuitinfodata"."circuit_speed" ASC
>>>

我注意到的一件事是,当我在上面打印物品时

#### with def __unicode__(self): #####

>>> from networks.models import CircuitInfoData
>>> d = CircuitInfoData.objects.only('provider').distinct()
>>> for i in d:
...  print i
...
Location1 | Showroom | BT | DSL | N/A
Location2 | Showroom | BT | MPLS | XXXX
Location2 | Showroom | KCOM | MPLS | XXXX
Location3 | Showroom | BT | MPLS | XXXX
Location3 | Showroom | BT | DSL | N/A
Location4 | Showroom | KCOM | MPLS | XXXXX
...

#### with out def __unicode__(self): #####

>>> from networks.models import CircuitInfoData
>>> d = CircuitInfoData.objects.only('provider').distinct()
>>> for i in d:
...  print i
...
CircuitInfoData_Deferred_circuit_bearer_circuit_cfb3d62ef325a6acfc8ddcb43c8ae1c6 object
CircuitInfoData_Deferred_circuit_bearer_circuit_cfb3d62ef325a6acfc8ddcb43c8ae1c6 object
CircuitInfoData_Deferred_circuit_bearer_circuit_cfb3d62ef325a6acfc8ddcb43c8ae1c6 object
CircuitInfoData_Deferred_circuit_bearer_circuit_cfb3d62ef325a6acfc8ddcb43c8ae1c6 object
CircuitInfoData_Deferred_circuit_bearer_circuit_cfb3d62ef325a6acfc8ddcb43c8ae1c6 object
CircuitInfoData_Deferred_circuit_bearer_circuit_cfb3d62ef325a6acfc8ddcb43c8ae1c6 object
...

#### with either ####

>>> for i in d:
...  print i.provider
...
BT
BT
KCOM
BT
BT
KCOM
...

1 个答案:

答案 0 :(得分:2)

distinct的文档说

  

返回在其SQL查询中使用SELECT DISTINCT的新QuerySet。   这样可以消除查询结果中的重复行。

     

默认情况下,QuerySet不会消除重复的行。在实践中,   这很少是一个问题,因为简单的查询如   Blog.objects.all()不会引入重复结果的可能性   行。

Distinct为您提供了不同的行,但您只查看记录中的一个字段,并且该字段中的项目可以重复,除非它具有唯一约束。在这种情况下,你不会。

如果你碰巧使用postgresql,你可以

CircuitInfoData.objects.distinct('provider')

实现您的目标。

<强>更新 由于您在评论中提到使用sqlite,请使用此解决方案。

CircuitInfoData.objects.values('provider').distinct()

这样可行,因为现在每行只有一列。生成的查询将类似于

SELECT DISTINCT "someapp_circuitinfodata"."name" FROM "someapp_circuitinfodata"

更新2:

请注意,您已覆盖__unicode__功能。

def unicode (个体经营):         返回&#39;%s | %s | %s | %s | %S&#39; %(self.showroom_config_data.location,self.major_site_info.location,self.provider,self.service_type,self.ref_no)

您指的是相关模型中的字段。这将是非常昂贵的(除非您使用select_related)。另请注意,如果您遍历查询集并使用print进行调试,则会给您带来误导性结果(因为您看到的是__unicode__的输出,这是一个相当复杂的函数)