I'm learning Django by building a simple recipes app. I have a 1 table model using the 'choices' field option for recipe categories rather than using a 2nd 'categories' table and a foreign key relationship. So i created db table via syncdb and then loaded table with test data. When i go to admin and click on the 'Recipes' link in an attempt to view recipes i get the following error:
Template error
In template /var/lib/python-support/python2.6/django/contrib/admin/templates/admin/change_list.html, error at line 34
Caught an exception while rendering: too many values to unpack
If anyone can shed light on this cryptic error that would be great. Db is Sqlite. Django version is 1.0. The model is listed below:
from django.db import models
class Recipe(models.Model):
CATEGORY_CHOICES = (
(1, u'Appetizer'),
(2, u'Bread'),
(3, u'Dessert'),
(4, u'Drinks'),
(5, u'Main Course'),
(6, u'Salad'),
(7, u'Side Dish'),
(8, u'Soup'),
(9, u'Sauce/Marinade'),
(10, u'Other'),
)
name = models.CharField(max_length=255)
submitter = models.CharField(max_length=40)
date = models.DateTimeField()
category = models.SmallIntegerField(choices=CATEGORY_CHOICES)
ingredients = models.TextField()
directions = models.TextField()
comments = models.TextField(null=True, blank=True)
Edit: Updated in light of kibibu's correction.
I have encountered what I believe is this same error, producing the message:
Caught ValueError while rendering: too many values to unpack
My form class was as follows:
class CalcForm(forms.Form):
item = forms.ChoiceField(choices=(('17815', '17816')))
Note that my choices type here a tuple. Django official documentation reads as follows for the choices arg:
An iterable (e.g., a list or tuple) of 2-tuples to use as choices for
this field. This argument accepts the same formats as the choices
argument to a model field.
src: https://docs.djangoproject.com/en/1.3/ref/forms/fields/#django.forms.ChoiceField.choices
This problem was solved by my observing the documentation and using a list of tuples:
class CalcForm(forms.Form):
item = forms.ChoiceField(choices=[('17815', '17816')])
Do note that while the docs state any iterable of the correct form can be used, a tuple of 2-tuples did not work:
item = forms.ChoiceField(choices=(('17815', '17816'), ('123', '456')))
This produced the same error as before.
Lesson: bugs happen.
You should use a ChoiceField instead of SmallIntegerField
If I had to guess, it's because whatever is in the administrative template expects a list of tuples, but you've instead supplied a tuple of tuples (hence the "too many values"). Try replacing with a list instead:
CATEGORY_CHOICES = [ # Note square brackets.
(1, u'Appetizer'),
(2, u'Bread'),
(3, u'Dessert'),
(4, u'Drinks'),
(5, u'Main Course'),
(6, u'Salad'),
(7, u'Side Dish'),
(8, u'Soup'),
(9, u'Sauce/Marinade'),
(10, u'Other'),
]
Per http://code.djangoproject.com/ticket/972 , you need to move the assignment CATEGORY_CHOICES = ... outside the class statement.
I got it working. Most of the 'too many values to unpack' errors that i came across while googling were Value Error types. My error was a Template Syntax type. To load my recipe table i had imported a csv file. I was thinking maybe there was a problem somewhere in the data that sqlite allowed on import. So i deleted all data and then added 2 recipes manually via django admin form. The list of recipes loaded after that.
thanks.
I just had the same problem... my cvs file came from ms excel and the date fields gotten the wrong format at saving time. I change the format to something like '2010-05-04 13:05:46.790454' (excel gave me 5/5/2010 10:05:47) and voilaaaa no more 'too many values to unpack’
kibibu's comment to Kreychek's answer is correct. This isn't a Django issue but rather an interesting aspect of Python. To summarize:
In Python, round parentheses are used for both order of operations and tuples. So:
foo = (2+2)
will result in foo being 4, not a tuple who's first and only element is 4: 4
foo = (2+2, 3+3)
will result in foo being a two-dimensional tuple: (4,6)
To tell Python that you want to create a one-dimensional tuple instead of just denoting the order of operations, use a trailing comma:
foo = (2+2,)
will result in foo being a one-dimensional tuple who's first and only element is 4: (4,)
So for your scenario:
class CalcForm(forms.Form):
item = forms.ChoiceField(choices=(('17815', '17816'),))
would give what you want. Using a list is a great solution too (more Pythonic in my opinion), but hopefully this answer is informative since this can come up in other cases.
For example:
print("foo: %s" % (foo))
may give an error if foo is an iterable, but:
print("foo: %s" % (foo,))
or:
print("foo: %s" % [foo])
will properly convert foo to a string whether it's an iterable or not.
Documentation: http://docs.python.org/2/tutorial/datastructures.html#tuples-and-sequences
This error IMO occurs when a function returns three values, and you assign it to 2. e.g.:
def test():
a=0
b=0
c=0
....
a,b=test() <---three values returned, but only assigning to 2.
a,b,c=test() <---three values returned, assigned to 3.OK
Related
I am new to django and trying to filter multiple fields that contain text.
columns = ['ticketId', 'checkSum']
q_objects = [Q(fieldname +'__contains', myString) for fieldname in columns]
objects = objects.filter(reduce(operator.or_, q_objects))
I get
Exception Type: ValueError
Exception Value: too many values to unpack on the "filter" last line. Any ideas
Try this:
Q(**{fieldname + '__contains': myString})
This is equivalent to providing a keyword argument, as you normally would when instantiating a Q object. For example:
Q(fieldname__contains=myString, another_fieldname__contains=myOtherstring)
The Q object essentially needs pairs of values to work. Looking at the code it seems you can also use tuples of length two, like this (I haven't tested, though):
Q(("fieldname__contains", myString), ("another_fieldname__contains", myOtherString))
What is the model you are querying? It looks like you left that out.
The last line,
objects = objects.filter(reduce(operator.or_, q_objects))
Should be something like
objects = MyModel.objects.filter(...)
In my Django form I have a ModelChoiceField for employees, but I want a choice in the dropdown for 'all' employees. What would be the best way to accomplish this?
employees = forms.ModelChoiceField(queryset=Employees.objects.all())
First attemptI tried
employees = forms.ChoiceField(choices = Employees.objects.values())
but I get a 'too many objects to unpack' error
Thanks
Try this:
employees = forms.ChoiceField(choices = [(emp['id'], emp['full_name'])
for emp in Employees.objects.values('id', 'full_name')])
The too many objects to unpack error raised because every cell of chioces must only contains two value similar below:
[(1, 'Eric Manson'), (2, 'Julia Rose'), (3, 'Saadi Khorshid'), ...]
But Employees.objects.values() unpacking all fields in dictionary form.
I have the following model schema in Django (with Postgres).
class A(Models.model):
related = models.ManyToManyField("self", null=True)
Given a QuerySet of A, I would like to return a dictionary mapping each instance of A in the QuerySet to a list of ids of its related instances as quickly as possible.
I can surely iterate through each A and query the related field, but is there a more optimal way?
According you have Three instances. You can use the values_list method to retrieve just the results and from this result get just the ID's of their related instances.
I use the pk field to be my filter because i don't know your scheme, but you can use anything, just must be a QuerySet.
>>> result = A.objects.filter(pk=1)
>>> result.values('related__id')
[{'id': 2}, {'id': 3}]
>>> result.values_list('related__id')
[(2,), (3,)]
>>> result.values_list('related__id', flat=True)
[2, 3]
You can get pretty close like this:
qs = A.objects.prefetch_related(Prefetch(
'related',
queryset=A.objects.only('pk'),
to_attr='related_insts')).in_bulk(my_list_of_pks)
This will give a mapping from pks of the current object to the instance itself, so you can iterate through as follows:
for pk, inst in qs.iteritems():
related_ids = (related.pk for related in inst.related_insts)
Or given an instance, you can do a fast lookup like so:
related_ids = (related.pk for related in qs[instance.pk]).
This method maps the instance ids to the related ids (indirectly) since you specifically requested a dictionary. If you aren't doing lookups, you may want the following instead:
qs = A.objects.prefetch_related(Prefetch(
'related',
queryset=A.objects.only('pk'),
to_attr='related_insts')).filter(pk__in=my_list_of_pks)
for inst in qs:
related_ids = (related.pk for related in inst.related_insts)
You may take note of the use of only to only pull the pks from the db. There is an open ticket to allow the use of values and (I presume) values_list in Prefetch queries. This would allow you to do the following.
qs = A.objects.prefetch_related(Prefetch(
'related',
queryset=A.objects.values_list('pk', flat=True),
to_attr='related_ids')).filter(pk__in=my_list_of_pks)
for inst in qs:
related_ids = inst.related_ids
You could of course optimize further, for example by using qs.only('related_insts') on the primary queryset, but make sure you aren't doing anything with these instances-- they're essentially just expensive containers to hold your related_ids.
I believe this is the best that's available for now (without custom queries). To get to exactly what you want, two things are needed:
The feature above is implemented
values_list is made to work with Prefetch to_attr like it does for annotations.
With these two things in place (and continuing the above example) you could do the following to get exactly what you requested:
d = qs.values_list('related_ids', flat=True).in_bulk()
for pk, related_pks in d.items():
print 'Containing Objects %s' % pk
print 'Related objects %s' % related_pks
# And lookups
print 'Object %d has related objects %s' % (20, d[20])
I've left off some details explaining things, but it should be pretty clear from the documentation. If you need any clarification, don't hesitate!
If you're using Postgres:
from django.contrib.postgres.aggregates import ArrayAgg
qs = A.objects.filter(pk__in=[1,2,6]).annotate(related_ids=ArrayAgg('related')).only('id')
mapping = {a.id: a.related_ids for a in qs}
You can also use filter/ordering in the ArrayAgg.
I wanted some guidance if possible on how to make this more generic:
def get_industry_choices(self):
industries = Industry.objects.all().order_by('name')
ind_arr = [(ind.id, ind.name) for ind in industries]
return ind_arr
Basically this function will return choices as expected for the forms.ChoiceField. I need to do this in a few places, and wanted to make the function above more generic. I know how to get the industries = Industry.objects.all().order_by('name') to be generic, but the 2nd part is what I'm not sure about. When creating the tuples, it has (ind.id, ind.name). the ind.name can be any value depending on the model passed in (it may not always have name in the model).
I tried to read up on this in a few places including:
Passing functions with arguments to another function in Python?
The above resource shows how to do it using a function passed in, but that seems a bit overkill? If I have to pass a function as an argument anyway, whats the point of making it more generic with one more function?
[EDIT]
Basically I want to produce something similar to this:
TITLE_CHOICES=(
(1, 'Mr.'),
(2, 'Ms.'),
(3, 'Mrs.'),
(4, 'Dr.'),
(5, 'Prof.'),
(6, 'Rev.'),
(7, 'Other'),
)
So when doing forms.ChoiceField I can pass in TITLE_CHOICES for example as the possible choices. The first value is the value I get when the form is submitted, the second value is what the user sees on form. I want to be able to programmatically create this with any model, I pass in the model name and one field in the above example, name. I want to create the tuple such that it is (id, name). But name could be replaced with anything in a different model...
It is hard to tell from your question, but I think the bit you are missing is getattr(). For example
ind = something()
for field in ['id', 'name']:
print getattr(ind, field)
Actually, Django already has a shortcut for this: values_list.
Industry.objects.all().values_list('id', 'name')
or
fields = ['id', 'name']
Industry.objects.all().values_list(*fields)
Maybe this helps:
from some_app.models import SomeModel
def generate_choices(model, order=None *args):
choices = model.objects
if order:
choices = choices.order_by(order)
return choices.values_list('pk', *args)
class MyForm(forms.Form):
my_choice_field = CharField(max_length=1,
choices=generate_choices(SomeModel, 'name'))
other_choice_field = CharField(max_length=1,
choices=generate_choices(SomeModel, 'city', 'state'))
Is it possible to filter a Django queryset by model property?
i have a method in my model:
#property
def myproperty(self):
[..]
and now i want to filter by this property like:
MyModel.objects.filter(myproperty=[..])
is this somehow possible?
Nope. Django filters operate at the database level, generating SQL. To filter based on Python properties, you have to load the object into Python to evaluate the property--and at that point, you've already done all the work to load it.
I might be misunderstanding your original question, but there is a filter builtin in python.
filtered = filter(myproperty, MyModel.objects)
But it's better to use a list comprehension:
filtered = [x for x in MyModel.objects if x.myproperty()]
or even better, a generator expression:
filtered = (x for x in MyModel.objects if x.myproperty())
Riffing off #TheGrimmScientist's suggested workaround, you can make these "sql properties" by defining them on the Manager or the QuerySet, and reuse/chain/compose them:
With a Manager:
class CompanyManager(models.Manager):
def with_chairs_needed(self):
return self.annotate(chairs_needed=F('num_employees') - F('num_chairs'))
class Company(models.Model):
# ...
objects = CompanyManager()
Company.objects.with_chairs_needed().filter(chairs_needed__lt=4)
With a QuerySet:
class CompanyQuerySet(models.QuerySet):
def many_employees(self, n=50):
return self.filter(num_employees__gte=n)
def needs_fewer_chairs_than(self, n=5):
return self.with_chairs_needed().filter(chairs_needed__lt=n)
def with_chairs_needed(self):
return self.annotate(chairs_needed=F('num_employees') - F('num_chairs'))
class Company(models.Model):
# ...
objects = CompanyQuerySet.as_manager()
Company.objects.needs_fewer_chairs_than(4).many_employees()
See https://docs.djangoproject.com/en/1.9/topics/db/managers/ for more.
Note that I am going off the documentation and have not tested the above.
Looks like using F() with annotations will be my solution to this.
It's not going to filter by #property, since F talks to the databse before objects are brought into python. But still putting it here as an answer since my reason for wanting filter by property was really wanting to filter objects by the result of simple arithmetic on two different fields.
so, something along the lines of:
companies = Company.objects\
.annotate(chairs_needed=F('num_employees') - F('num_chairs'))\
.filter(chairs_needed__lt=4)
rather than defining the property to be:
#property
def chairs_needed(self):
return self.num_employees - self.num_chairs
then doing a list comprehension across all objects.
I had the same problem, and I developed this simple solution:
objects = [
my_object
for my_object in MyModel.objects.all()
if my_object.myProperty == [...]
]
This is not a performatic solution, it shouldn't be done in tables that contains a large amount of data. This is great for a simple solution or for a personal small project.
PLEASE someone correct me, but I guess I have found a solution, at least for my own case.
I want to work on all those elements whose properties are exactly equal to ... whatever.
But I have several models, and this routine should work for all models. And it does:
def selectByProperties(modelType, specify):
clause = "SELECT * from %s" % modelType._meta.db_table
if len(specify) > 0:
clause += " WHERE "
for field, eqvalue in specify.items():
clause += "%s = '%s' AND " % (field, eqvalue)
clause = clause [:-5] # remove last AND
print clause
return modelType.objects.raw(clause)
With this universal subroutine, I can select all those elements which exactly equal my dictionary of 'specify' (propertyname,propertyvalue) combinations.
The first parameter takes a (models.Model),
the second a dictionary like:
{"property1" : "77" , "property2" : "12"}
And it creates an SQL statement like
SELECT * from appname_modelname WHERE property1 = '77' AND property2 = '12'
and returns a QuerySet on those elements.
This is a test function:
from myApp.models import myModel
def testSelectByProperties ():
specify = {"property1" : "77" , "property2" : "12"}
subset = selectByProperties(myModel, specify)
nameField = "property0"
## checking if that is what I expected:
for i in subset:
print i.__dict__[nameField],
for j in specify.keys():
print i.__dict__[j],
print
And? What do you think?
i know it is an old question, but for the sake of those jumping here i think it is useful to read the question below and the relative answer:
How to customize admin filter in Django 1.4
It may also be possible to use queryset annotations that duplicate the property get/set-logic, as suggested e.g. by #rattray and #thegrimmscientist, in conjunction with the property. This could yield something that works both on the Python level and on the database level.
Not sure about the drawbacks, however: see this SO question for an example.