I have the following code.
queryset = Registry.objects.filter(
epas_id__contains=uuid_obj_id
).values_list('pk', flat=True)
Based on my data, this correctly returns the following:
<QuerySet [UUID('d9a0977c-5bc0-4667-af24-5e95b83761d4'), UUID('b2d0f086-0a55-44cc-b1ba-3ebf598d24ae')]>
But what I want to do is extract just the values of pk in a list, so something like this:
['d9a0977c-5bc0-4667-af24-5e95b83761d4', 'b2d0f086-0a55-44cc-b1ba-3ebf598d24ae']
Any thoughts and help on how I can achieve this would be appreciated.
We can work with list comprehension, and call str(…) on each element, like:
queryset = Registry.objects.filter(
epas_id__contains=uuid_obj_id
).values_list('pk', flat=True)
result = [str(pk) for pk in queryset]
Related
I have some python code:
UnitTestCollection.objects.filter(unit__type=unit_type)
which outputs data in format:
<QuerySet [<UnitTestCollection: VALUE1>, <UnitTestCollection: VALUE2>...
How can I extract a list of the values only i.e.
[VALUE1, VALUE2....]
Why not a simple list comprehension?
qs = UnitTestCollection.objects.filter(unit__type=unit_type)
my_values = [item.field_name for item in qs]
Or use values_list() to just fetch the specific field for each item directly in your queryset, with the advantage of lazy evaluation:
qs = UnitTestCollection.objects.filter(unit__type=unit_type)\
.values_list('field_name', flat=True)
values_list is better than a list comprehension because querysets are lazily evaluated. They won't be executed until you actually need them.
queryset = UnitTestCollection.objects.filter(unit__type=unit_type).values_list('<insert field>', flat=True)
This will return [field1, field2, field3...]
if you use .values('<insert field>') you'll get [{field: field value1}, {field: field value2}, {field: field value3}...]
We are doing search in django and we have two query sets: one AND queryset and one OR queryset.
q_list = [Q(x) for x in predicates if x[1]]
_filter_AND = reduce(operator.and_, q_list)
_filter_OR = reduce(operator.or_, q_list)
_queryset_AND = queryset.filter(_filter_AND)
_queryset_OR = queryset.filter(_filter_OR).exclude(id__in=[c.id for c in _queryset_AND])
queryset = list(chain(_queryset_AND, _queryset_OR))
Now, when returning, data all the data is mixed. Also, I want to have the results from AND queryset to appear first.
Would anyone know how to do that in django?
Thanks in advance!
I am trying to run a queryset with the value of the filter being the values inside a dictionary.
latest_entries = Entry.objects.filter(zipcode__in=nearestzips.values())
print latest_entries
>>>TypeError: Cannot use a multi-field GeoValuesQuerySet as a filter value.
second attempt
latest_entries = Entry.objects.filter(zipcode__in=nearestzips.values_list('code', flat=True))
print latest_entries
>>>ProgrammingError: invalid reference to FROM-clause entry for table "cities_postalcode" HINT perhaps you meant to reference the table alias"u0"
How can I accomplish this? Should I just take the extra step of creating a new list and appending the dictionary values into the list? And then run the queryset on the list? I'm not sure what to do.
EDIT:
when I print nearestzips I get:
[<PostalCode:97201>,<PostalCode:97202>]
BUT, when I print nearestzips.values(), I get:
[distance:0, code: 97201, name: Portland, subregion: Multnomah] etc.
Looks like the nearestzips is a subclass of the QuerySet which is lost some compatibility. Try to convert values_list() to the simple python list:
zip_codes = list(nearestzips.values_list('code', flat=True))
latest_entries = Entry.objects.filter(zipcode__in=zip_codes)
in a view I am constructing I need to consult multiple databases. What I want to do is use the results of on query_set to search another db table.
I have functioning mydb1_query_set, what I need now is something like this:
for row in mydb1_query_set:
mydb2_query_set = Mytable.objects.filter(id=row.id)
So that I keep adding to the initially empty mydb2_query_set as I iterate. I realize that there is no QuerySet.append, so how do I achieve what I want? Any help much appreciated...
Use a list instead of a queryset, and then you can append or extend as you wish.
mydb2_query = []
for row in mydb1_query_set:
mydb2_query.extend(list(Mytable.objects.filter(id=row.id)))
qs1= <QuerySet [<User: 1#gmail.com>, <User: 2#gmail.com>]>
qs2= <QuerySet [<User: 3#gmail.com>, <User: 4#gmail.com>]>
qs3 = qs1 | qs2
res:
qs3 = <QuerySet [<User: 1#gmail.com>, <User: 2#gmail.com>, <User:3#gmail.com>, <User: 4#gmail.com>]>
EDIT: Link to documentation:
https://docs.djangoproject.com/en/2.1/ref/models/querysets/#operators-that-return-new-querysets
Using python's built in itertools module worked best for me.
from itertools import chain
qs1 = Mytable.objects.filter(id=2)
qs2 = Mytable.objects.filter(id=3)
all_queries = chain(qs1, qs2)
Here's the docs, in case you'd like some reference materials: https://docs.python.org/3/library/itertools.html#itertools.chain
Django's Managers object provide a default method called .get_queryset() which allow you to concatenate extra queries after it:
queryset = MyModel.objects.get_queryset()
if username:
queryset = queryset.filter(username=username)
if country:
queryset = queryset.filter(country=country)
You could easily using .query attribute getting the SQL, for example:
>>> print(queryset.query)
SELECT `myapp_mymodel`.`id`, `myapp_mymodel`.`username`, `myapp_mymodel`.`country` FROM `myapp_mymodel` WHERE `myapp_mymodel`.`country` = foo
I have a third-party function which gives me a filtered queryset (e.g. records with 'valid'=True) but I want to remove a particular condition (e.g. to have all records, both valid and invalid).
Is there a way to remove a filter condition to an already-filtered queryset?
E.g.
only_valid = MyModel.objects.filter(valid=True)
all_records = only_valid.**remove_filter**('valid')
(I know that it would be better to define 'all_records' before 'only_valid', but this is just an example...)
Although there is no official way to do this using filter notation, you may easily do it with Q-notation.
For example, if you ensure that third-part function returns a Q object, not a filtered QuerySet, you may do the following:
q = ThirdParty()
q = q | Q(valid=False)
And the resulting SQL conditions will be joined using OR operator.
From the docs:
Each time you refine a QuerySet, you get a brand-new QuerySet that is in no way bound to the previous QuerySet. Each refinement creates a separate and distinct QuerySet that can be stored, used and reused.
I doubt therefore, that there is a standard way to do it. You could dig into the code, see, what filter() does and try a bit. If that doesn't help, my assumption is, you're out of luck and need to re-build the query yourself.
Use this function
from django.db.models import Q
def remove_filter(lookup, queryset):
"""
Remove filter lookup in queryset
```
>>> queryset = User.objects.filter(email='user#gmail.com')
>>> queryset.count()
1
>>> remove_filter('email', queryset)
>>> queryset.count()
1000
```
"""
query = queryset.query
q = Q(**{lookup: None})
clause, _ = query._add_q(q, self.used_aliases)
def filter_lookups(child):
return child.lhs.target != clause.children[0].lhs.target
query.where.children = list(filter(filter_lookups, query.where.children))
Here's what I did in a similar case.
all_records = MyModel.objects.all()
only_valid = MyModel.objects.filter(valid=True)
only_valid.original = all_records
...
all_records = only_valid.original
Obviously this clears any other filters too so it won't be right for every case.
original_query_set = MyModel.objects.filter(**conditions)
model_class = orginal_query_set.model
new_query_set = model_class.objects.filter(**new_conditions)
You can use the .model attribute on a QuerySet to get the model class, then use the model class to make a brand new QuerySet.
Thanks for making me check the source code Boldewyn. So, it seems there's a new method right below filter() with the same parameters... called exclude() (as of commit mini-hash ef6c680, for when it loses its line number)
Return a new QuerySet instance with NOT (args) ANDed to the existing set.
So, to answer the original question:
only_valid = MyModel.objects.filter(valid=True)
filtered_results = only_valid.exclude(the_condition_to_remove=True)