Running into issues with Django's ModelChoiceField "queryset" attribute - python

In django by default the form for a model foreign key is a ModelChoiceField (where you can select out of a list of all possible models). And it's possible to change these with the query set attribute, like
// in forms.py
self.fields['possible_cars'].queryset = somequeryset
But I'm in a situation where I have a list of stuff, not a queryset, and since there is no way to convert a list into a queryset, i'm not sure how to make the options for my ModelChoiceField similar to the list of models I want. (Since they take a queryset by default, i'm assuming they get a list from that query anyways, so this kinda thing should be possible).
I tried self.fields['possible_cars']._choices = mylist , but it won't work.
Any ideas guys?

Assuming your field take a Car queryset, you can construct one like the following:
mylist = ['BMW', 'Lamborghini', 'Porsche']
cars = Car.objects.filter(name__in=mylist)
self.fields['possible_cars'].queryset = cars

Related

How to use django ORM to query database

I have a model called 'dboinv_product' and this model has a field called 'product_name'
I need to use Django ORM in my views.py file to pull ALL the product names. The goal is to put it into a list this way I can serialize it using JSON.
Does anyone know which Django command(s) can be used to produce this list?
Essentially, I need the equivalent of "SELECT ALL product_name FROM dbo.inv_product"
values_list is what you are looking for.
value= dboinv_product.objects.values_list('product_name', flat=True)
list = list(value) # to convert to a list
# flat=True to get list rather than tuple inside of the ValuesListQuerySet.
The document about values_listis here. 1

Django remove duplicates from queryset

i want to remove duplicates in relative fields, my queryset example:
example = models.Object.objects.values('name', 'photo__name', 'url', 'photo__url').distinct()
if name == photo__name and url == photo_url i need to delete one of them, how can i do this with Django ORM or i need to iterate through queryset?
If you are using PostgreSQL, check out the Django docs on distinct():
On PostgreSQL only, you can pass positional arguments (*fields) in order to specify the names of fields to which the DISTINCT should apply...
When you specify field names, you must provide an order_by() in the QuerySet, and the fields in order_by() must start with the fields in distinct(), in the same order.
Thus, in your example, you can remove duplicates on certain fields by using:
.order_by('photo__name', 'photo__url').distinct('photo__name', 'photo__url')
To reference fields of model in filtering you can use Django ORM F function: https://docs.djangoproject.com/en/dev/topics/db/queries/#filters-can-reference-fields-on-the-model
But i guess you cannot delete one of them :) You got to decide which one you want to delete
UPDATE
Look when you filter like Object.objects.filter(photo__name='something') you filter Object table by related photo name. So you dealing with join over two tables. If you want to exclude objects with name = related photo name you should do something like this
from django.db.models import F
Object.objects.exclude(name=F('photo__name'))
Is that useful?

Django: Most Efficient Way To Filter A Queryset Repeatedly

I have a model that looks something like this:
class Item(models.Model):
name = models.CharField()
type = models.CharField()
tags = models.models.ManyToManyField(Tags)
In order to render a given view, I have a view that presents a list of Items based on type. So in my view, there's a query like:
items = Item.objects.filter(type='type_a')
So that's easy and straight forward. Now I have an additional requirement for the view. In order to fulfill that requirement, I need to build a dictionary that relates Tags to Items. So the output i am looking for would be something like:
{
'tag1': [item1, item2, item5],
'tag2': [item1, item4],
'tag3': [item3, item5]
}
What would be the most efficient way to do this? Is there any way to do this without going to the database with a new query for each tag?
You can check prefetch_related it might help you:
This has a similar purpose to select_related, in that both are designed to stop the deluge of database queries that is caused by accessing related objects, but the strategy is quite different... prefetch_related, on the other hand, does a separate lookup for each relationship, and does the ‘joining’ in Python. This allows it to prefetch many-to-many and many-to-one objects, which cannot be done using select_related...
So in the end you will either do multiple queries or use prefetch_related and it will do some Python joins on the objects.
You might do something like this:
# This should require two database queries, one for the items
# and one for all the associated tags.
items = Item.objects.filter(type='type_a').prefetch_related('tags')
# Now massage the data into your desired data structure.
from collections import defaultdict
tag_dict = defaultdict(list)
for item in items:
# Thanks to prefetch_related this will not hit the database.
for tag in item.tags.all():
tag_dict[tag].append(item)

Variable interpolation in python/django, django query filters [duplicate]

Given a class:
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=20)
Is it possible, and if so how, to have a QuerySet that filters based on dynamic arguments? For example:
# Instead of:
Person.objects.filter(name__startswith='B')
# ... and:
Person.objects.filter(name__endswith='B')
# ... is there some way, given:
filter_by = '{0}__{1}'.format('name', 'startswith')
filter_value = 'B'
# ... that you can run the equivalent of this?
Person.objects.filter(filter_by=filter_value)
# ... which will throw an exception, since `filter_by` is not
# an attribute of `Person`.
Python's argument expansion may be used to solve this problem:
kwargs = {
'{0}__{1}'.format('name', 'startswith'): 'A',
'{0}__{1}'.format('name', 'endswith'): 'Z'
}
Person.objects.filter(**kwargs)
This is a very common and useful Python idiom.
A simplified example:
In a Django survey app, I wanted an HTML select list showing registered users. But because we have 5000 registered users, I needed a way to filter that list based on query criteria (such as just people who completed a certain workshop). In order for the survey element to be re-usable, I needed for the person creating the survey question to be able to attach those criteria to that question (don't want to hard-code the query into the app).
The solution I came up with isn't 100% user friendly (requires help from a tech person to create the query) but it does solve the problem. When creating the question, the editor can enter a dictionary into a custom field, e.g.:
{'is_staff':True,'last_name__startswith':'A',}
That string is stored in the database. In the view code, it comes back in as self.question.custom_query . The value of that is a string that looks like a dictionary. We turn it back into a real dictionary with eval() and then stuff it into the queryset with **kwargs:
kwargs = eval(self.question.custom_query)
user_list = User.objects.filter(**kwargs).order_by("last_name")
Additionally to extend on previous answer that made some requests for further code elements I am adding some working code that I am using
in my code with Q. Let's say that I in my request it is possible to have or not filter on fields like:
publisher_id
date_from
date_until
Those fields can appear in query but they may also be missed.
This is how I am building filters based on those fields on an aggregated query that cannot be further filtered after the initial queryset execution:
# prepare filters to apply to queryset
filters = {}
if publisher_id:
filters['publisher_id'] = publisher_id
if date_from:
filters['metric_date__gte'] = date_from
if date_until:
filters['metric_date__lte'] = date_until
filter_q = Q(**filters)
queryset = Something.objects.filter(filter_q)...
Hope this helps since I've spent quite some time to dig this up.
Edit:
As an additional benefit, you can use lists too. For previous example, if instead of publisher_id you have a list called publisher_ids, than you could use this piece of code:
if publisher_ids:
filters['publisher_id__in'] = publisher_ids
Django.db.models.Q is exactly what you want in a Django way.
This looks much more understandable to me:
kwargs = {
'name__startswith': 'A',
'name__endswith': 'Z',
***(Add more filters here)***
}
Person.objects.filter(**kwargs)
A really complex search forms usually indicates that a simpler model is trying to dig it's way out.
How, exactly, do you expect to get the values for the column name and operation?
Where do you get the values of 'name' an 'startswith'?
filter_by = '%s__%s' % ('name', 'startswith')
A "search" form? You're going to -- what? -- pick the name from a list of names? Pick the operation from a list of operations? While open-ended, most people find this confusing and hard-to-use.
How many columns have such filters? 6? 12? 18?
A few? A complex pick-list doesn't make sense. A few fields and a few if-statements make sense.
A large number? Your model doesn't sound right. It sounds like the "field" is actually a key to a row in another table, not a column.
Specific filter buttons. Wait... That's the way the Django admin works. Specific filters are turned into buttons. And the same analysis as above applies. A few filters make sense. A large number of filters usually means a kind of first normal form violation.
A lot of similar fields often means there should have been more rows and fewer fields.

Adding custom Field to django queryset containing source record

Is it possible to add a field to a queryset in django which would do the following:
fitting_set_items_list = FittingSetItem.objects.exclude(fitting_pack = None).exclude(fitting_pack = '').order_by('usage_type')
fitting_pack_list = FittingPack.objects.filter(fittingsetitem__in=fitting_set_items_list).add_field({'fitting_set_item': fittingsetitem})
This way i could use:
for fitting_pack_item in fitting_pack_item_list:
fitting_set_item = fitting_pack_item.fitting_set_item
and it'd have the FittingSetItem that i came from in the first place.
The overall Idea is that Many FittingSetItems can point to a FittingPack, so i want to be able to know which FittingSetItem my FittingPack was sourced from, and the easiest way i saw was to have the reverse FK on the FittingPack. This would allow me to go backwards and forwards on possibly ambiguous FK relations
I assume this is what you seek, if FittingSetItem.fitting_pack is a ForeignKey
fitting_packs = FittingPack.objects.filter(fittingsetitem__fitting_pack__isnull=False)
It gets the fitting packs linked by a set item. You might add .distinct() or replace fittingsetitem with fitting_set_item.

Categories

Resources