Django дает TypeError при использовании len () на QuerySet - PullRequest
4 голосов
/ 11 июня 2011

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

listCompetition = Competition.objects.filter(compId=competitionId)
if len(listCompetition) == 0:
   #some code here
else:
   #some code here

выдает следующую ошибку:

File "C:\Users\admin\workspace\project\src\bla\bla\module.py", line 222, in getMatches
   if len(listCompetition) == 0:
File "C:\Python27\lib\site-packages\django\db\models\query.py", line 82, in __len__
   self._result_cache = list(self.iterator())
File "C:\Python27\lib\site-packages\django\db\models\query.py", line 286, in iterator
   obj = model(*row[index_start:aggregate_start])
TypeError: __init__() takes exactly 3 arguments (4 given)

Однако, если я подставлю первую строку кода следующим образом:

listCompetition = list(Competition.objects.filter(compId=competitionId))

тогда отлично работает. Почему он ведет себя так странно? Как получается, что Django передает 4 параметра, если я определил только два в конструкторе класса Competition? Если это поможет, вот определение модели для класса Competition:

class Competicion(MultiName):
   def __init__(self, canonicalName, compId):
      super(Competition, self).__init__(canonicalName, compId)

class MultiName(models.Model):
   entId = models.CharField(null=True, max_length=25); 
   canonicalName = models.CharField(max_length=50, primary_key=True);

   def __init__(self, canonicalName, entId=None):
      super(MultiName, self).__init__()
      self.canonicalName = canonicalName;
      self.entId = entId;

Большое спасибо.

Ответы [ 3 ]

5 голосов
/ 11 июня 2011

Простой: в первом случае вы получаете объект набора запросов, а не список.Querysets являются итераторами.Объекты списков также являются итераторами, но итераторы не являются списками.

Django делает это для оптимизации памяти и производительности: база данных сохраняет набор, а Django читает ответ по одному элементу за раз, каждый раз, когда вы запрашиваете объектиз набора запросов.Использование list() заставляет Django прочитать весь ответ и упаковать его в объект списка.Если возвращаемый набор очень большой, это может быть проблематично.

Чтобы узнать, насколько велик набор запросов, используйте метод Queryset.count().

3 голосов
/ 11 июня 2011

Он нарушен, потому что вы нарушили соглашения, используемые моделями Django, когда вы переопределили __init__.Почему вы все равно используете __init__?То, что вы реализуете ... уже реализовано.

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

Чтобы исправить свой код, измените его на следующее:

class Competition(MultiName):
    def __init__(self, *args, **kwargs):
        if "compId" in kwargs:
            kwargs["entId"] = kwargs.pop("compId")
        super(Competition, self).__init__(*args, **kwargs)

class MultiName(models.Model):
    entId = models.CharField(null=True, max_length=25); 
    canonicalName = models.CharField(max_length=50, primary_key=True);

Там много отличной документациидля моделей , которые охватывают этот материал.

0 голосов
/ 11 июня 2011

вместо

if len(listCompetition) == 0:

использование

if listCompetition.count() == 0:

или, возможно,

if not listCompetition.exists():
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...