I am programming a very simple application to store results of soccer matches, and I am stuck with the following problem. When running one of the unit tests, the following code:
listCompetition = Competition.objects.filter(compId=competitionId)
if len(listCompetition) == 0:
#some code here
else:
#some code here
gives the following error:
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)
However, if I substitute the first line of code by:
listCompetition = list(Competition.objects.filter(compId=competitionId))
then it works perfectly fine. Why does it behave in this strange way? How comes that Django is passing 4 parameters, if I have defined only two in the constructor of class Competition? If it helps, here is the model definition for class 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;
Thank you very much.
Simple: in your first case, you're getting back a queryset object, not a list. Querysets are Iterators. List objects are also Iterators, but Iterators are not lists.
Django does this to optimize memory and performance: the database keeps the set, and Django reads the response one item at a time, each time you request an object from the queryset. Using list()
causes Django to read the entire response and pack it into a list object. If the return set is very large, this can be problematic.
To know how big a queryset is, use the Queryset.count()
method instead.
Instead of
if len(listCompetition) == 0:
use
if listCompetition.count() == 0:
or perhaps
if not listCompetition.exists():
It's broken because you've broken the conventions in use by Django models when you overrode __init__
. Why are you implementing __init__
anyway? What you're implementing is… already implemented.
You seem to be making assumptions about how to use Django that are unfounded. I suggest you read the tutorial before proceeding.
To fix your code, change it to the following:
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);
There's a lot of great documentation for models that covers this stuff.
精彩评论