Django Q set too many values to unpack - python

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(...)

Related

Django: annotate queryset with string

I need to annotate a queryset with strings from dictionary. The dictionary keys come from the model's field called 'field_name'.
I can easily annotate with strings from dictionary using the Value operator:
q = MyModel.objects.annotate(
new_value=Value(value_dict[key], output_field=CharField()))
And I can get the field value from the model with F expression:
q = MyModel.objects.annotate(new_value=F('field_name'))
Putting them together however fails:
# doesn't work, throws
# KeyError: F(field_name)
q = MyModel.objects.annotate(
new_value=Value(value_dict[F('field_name')],
output_field=CharField()))
Found this question, which afaiu tries to do the same thing but that solution throws another error:
Unsupported lookup 'field_name' for CharField or join on the field not permitted.
I feel like I'm missing something really obvious here but I just can't get it to work. Any help appreciated.
Right, just as I thought, a tiny piece was missing. The Case(When(... solution in the linked question worked, I just needed to wrap the dictionary value in Value() operator as follows:
qs = MyModel.objects.annotate(
new_value=Case(
*[ When(field_name=k, then=Value(v)) for k,v in value_dict.items() ],
output_field=CharField()
)
)

queryset filter according to only first line - Django

Tying to filter data using queryset.filter() in Django. but it returns not what I expecting. can someone correct me.
single data cell looks like below.(each line separated by \n)
こちらは1行です。(0.57)\n
こちらは2行です。(0.67)\n
こちらは3行です。(0.77)\n
こちらは4行です。(0.87)\n
こちらは5行です。(0.697)
code like below
queryset = queryset.filter(predicted_result__regex = r"\A.*", predicted_result__contains='(0.5') |\
queryset.filter(predicted_result__regex = r"\A.*", predicted_result__contains='(0.6') |\
queryset.filter(predicted_result__regex = r"\A.*", predicted_result__contains='(0.7')
output:
this will be considering all 5 lines not only the first line.
target:
only get values contains in first line between score (inside brackets)0.5 to 0.8. all the other lines should omit.
expected result:
こちらは1行です。(0.57)\n
The problem with your current query is that your 'single data cell' is currently a string. Using a regex to calculate what may or may not be expected will still return the entire string on 'True'. You should separate the 'text' from the 'float' values in order to query more efficiently.
class Model(model):
descriptor = models.CharField()
value = models.FloatField()
Now you can actually query the 'value' on it's own.
If you are unable to change the model for whatever reason, you need to do multiple queries and use the union/intersection/difference methods.
fives_queryset = queryset.filter(predicted_result__contains'(0.5')
sixes_queryset = queryset.filter(predicted_result__contains'(0.6')
sevens_queryset = queryset.filter(predicted_result__contains'(0.7')
result_queryset = union(fives_queryset, sixes_queryset, sevens_queryset)

Django filtering AND loop in a Django on M2M field

I have a list of IDs I need to query and filter (using AND) in Django. I would like to use something along the lines of example 2 below but it gives incorrect results 0. The models are simple, Many Products can have Many Tags. What is wrong with example 2?
Correct Results
Example 1:
q = Product.objects.all()
for id in _list_of_ids:
q.filter(tags__id=id)
Example 2:
Incorrect results but seems better (edited for brevity) ...
for id in _list_of_ids:
q = Q(tags__id=id)
# apend q here etc
# q = (AND: ('tags__id', 1), ('tags__id', 2))
Products.objects.filter(q)
What you are searching for is:
products = reduce(lambda qs, p_id: qs.filter(tags=p_id), _list_of_ids, Product.objects.all())
Basically there is a difference between a single .filter call with several Q objects and multiple .filter calls each one with a single Q object.
In the first scenario you get one inner join with all Q filters applied to it.
In the second scenario you get many inner joins, each applying only one Q object.
In your case, when you are searching for a product, having a combination of multiple tags, you need to make an inner join per tag in order to find such a product (this is the second scenario) so you need many .filter calls.
More about that in the docs: Spanning multi-valued relationships
What is the full code for Example 2?
Something like this seems like it should work...
q_expression = [Q("tags__", id) for id in list_of_ids]
queryset = Product.objects.filter(reduce(operator.and_, q_expression))
q = Product.objects.filter(tags__id__in=list_of_ids)

TestCase self.assertEqual does not match a similar string

I'am trying to create a model unittest for a ManyToMany relationship.
The aim is to check, if there is the right category saved in the table Ingredient.
class IngredientModelTest(TestCase):
def test_db_saves_ingredient_with_category(self):
category_one = IngredientsCategory.objects.create(name='Food')
first_Ingredient = Ingredient.objects.create(name='Apple')
first_Ingredient.categories.add(category_one)
category_two = IngredientsCategory.objects.create(name='Medicine')
second_Ingredient = Ingredient.objects.create(name='Antibiotics')
second_Ingredient.categories.add(category_two)
first_ = Ingredient.objects.first()
self.assertEqual('Apple', first_.name)
self.assertEqual(first_.categories.all(), [category_one])
self.assertEqual(first_, first_Ingredient)
for self.asserEqual(first_.categories.all(), [category_one]) in the second last row I get this weird assert:
AssertionError: [<IngredientsCategory: Food>] != [<IngredientsCategory: Food>]
I tried many other different ways, but none of it worked. Does any one suppose how I can get the information of first_.categories.all() to compare it with something else?
That'll be because they're not equal - one is a QuerySet, the other is a list - they just happen to have the same str representations.
You could either cast the QuerySet to a list with list(first_.categories.all()), or a possible solution for this situation may be:
self.assertEqual(first_.categories.get(), category_one)

Django/ Python - max() of list returns a tuple

Hi I have a Django function:
def get_spans(angle):
spans = Spans.objects.values_list('span').filter(
max_roof_angle=angle,
)
try:
max_span = max(spans)
except ValueError:
max_span = 0
return max_span
My question is - why does this return a tuple? How do I ensure I am getting a single, integer value back?
Any help much appreciated.
From the documentation: you can get a flat list using the arg flat=True. If you try to get the max from a list you would get a single value which you need
def get_spans(angle):
spans = Spans.objects.values_list('span', flat=True).filter(
max_roof_angle=angle,
)
max_span = max(spans)
return max_span
Raunak already gave the proper answer for how to get the integer using value_list(), but I thought I might add that the reason why it returns a tuple is so that you can query multiple fields. Because Python doesn't treat single-element tuples like scalars, it would be inconsistent to return a scalar in some cases but a tuple in others.
But also, a better way to get the max would be to let the database calculate it for you, using aggregation. That way you can add db_index=True to the span field in your model and have the DB calculate the max in O(1) time. I can't really test it, but something like this should do the trick, I think:
from django.db.models import Max
def get_spans(angle):
return Spans.objects.filter(max_roof_angle_exact=angle).aggregate(Max('span'))['span__max']
You can return max_span[0]
I would suggest checking that it isn't an empty tuple. So do the proper exception handling too.

Categories