I am trying to get access to the instances of a ModelChoiceField to render them the way I want in a template by displaying several fields of the instances.
class MyForm(forms.Form):
mychoices = forms.ModelChoiceField(
queryset=ObjectA.objects.all(), widget=forms.RadioSelect(), empty_label=None
)
This does not work:
{% for choice in form.mychoices %}
{{ choice.pk}}
{% endfor %}
I also tried to use the queryset but it does not render anything
{% for choice in form.mychoices.queryset %}
{{ choice.pk}}
{% endfor %}
Any idea?
Thanks
{% for choice in form.mychoices.field.queryset %}
{{ choice.pk }}
{% endfor %}
Notice the extra .field. It's a bit strange the first time you come across it, but it gives you what you want. You can also access the choices attribute of that object, instead of accessing queryset directly, but you'll need to access the first element of the choice to get the PK of the instance, like this:
{% for choice in form.mychoices.field.choices %}
{{ choice.0 }}
{% endfor %}
Related
Models:
class House(Model)
class Flat(Model):
house = ForeignKey(House, related_name="houses")
owner = ForeignKey(User)
class User(Model)
queryset:
queryset = User.objects.prefetch_related(
Prefetch("flats", queryset=Flat.objects.select_related("houses"))
And then flats:
{% for flat in user.flats.all %}
<p>№ {{ flat.number }}, {{ flat.house.name }}</p>
{% endfor %}
It's fine. But for houses I need only unique ones
{% for flat in user.flats.all %}
<p>House {{ flat.house.name }}</p>
{% endfor %}
But this template gives me ALL houses, with duplicates.
How can I avoid duplicates, any ideas? I tried .distinct() but it's dosen't work, looks like I using distinct() wrong or etc.
It seems you may end up with duplicate houses if a user is the owner of multiple flats, which are all in the same house. To get all houses that the user is related to via Flats, you can use a different query, starting with House so that you can use distinct:
distinct_houses = House.objects.filter(flats__owner=user).distinct()
The above returns one House object for each flat where the user is an owner, and makes sure you don't have duplicates. (Note that the above assumes the related_name is changed to flats for house = ForeignKey(House, related_name="flats"), since "houses" as the related_name seems like a typo to relate back to the Flat model.)
Alternatively, you could do something in-memory in Python, if you still also need to know all Flats via your original queryset = User.objects.prefetch_related(...) and don't want an additional query. Like:
distinct_houses = {flat.house for flat in user.flats.all()}
Side note: it looks like you have a typo in needing to use Flat.objects.select_related('house') rather than Flat.objects.select_related('houses') based on the Foreign Key field name being house.
Only found solution with template filters.
Queryset:
queryset = User.objects.filter(status="ACTIVE").prefetch_related(
Prefetch("flats", queryset=Flat.objects.select_related("house"))
)
With this I can get all flats for each user:
{% for user in object_list %}
{% for flat in user.flats.all %}
{{ flat.number }}, {{ flat.house.name }}
{% endfor %}
{% endfor %}
And I am using template filter to get unique houses.
{% for user in object_list %}
{% for flat in user.flats.all|get_unique_houses %}
{{ flat.house.name }}
{% endfor %}
{% endfor %}
# extra_tags.py
#register.filter(name="get_unique_houses")
def get_unique_houses(value):
return value.distinct('house')
Doing this works
{% for comment in comments %}
{{ comment.user }}
{% endfor %}
However, I want to get all the comment.user values in the dictionary without using a for loop. Is this possible?
I ask because I need to do this check
{% if name in comment.user %} # check if name is in any one of the comments
# do something
{% endif %}
Basically, you need to get all the distinct users from comments. You have to do it in the view and pass users queryset back into the template:
users = User.objects.filter(comment__in=comments).distinct()
I have several models in my application, and as I will have some views doing the same thing (form + tables showing existing records in my model), but implemented dfferently because of the model, which will be different in each case, I was wondering if it was possible to make it generic.
I googled a bit and was not able to find anything relevant to my case.
What I would like to achieve:
In my view, I want to go through each object from the model that I passed to the template, for example:
return render_template('addstatus.html', form=form, statuses=Status.query.all(),
target_model="Status", fields=Status.__mapper__.c.keys())
But I want to have only one view, whatever the model will be, so I am not able to know in advance the fields of my model, the number of columns and so on.
I want to have something like that in my view:
{% for obj in objects %}
{% for field in obj.fields %} (not existing)
<h1> {{ field }} :: {{ obj.fields.field.value }}
{% endfor %}
{% endfor %}
Is it something possible? How can I achieve that?
You can add this method to your db.Model class (either by subclassing or by monkeypatching):
from sqlalchemy.orm import class_mapper, ColumnProperty
def columns(self):
"""Return the actual columns of a SQLAlchemy-mapped object"""
return [prop.key for prop in class_mapper(self.__class__).iterate_properties
if isinstance(prop, ColumnProperty)]
Then you can use {% for col in obj.columns() %} to iterate over the column names.
I had a similar issue, and wanted something purely Jinja2 based. This will return all of the keys/fields in your "obj" table, and worked well for me:
obj.__table__.columns._data.keys()
Here it is implemented in your sample code
{% for obj in objects %}
{% for field in obj.__table__.columns._data.keys() %}
<h1> {{ field }} :: {{ obj[field] }} </h1>
{% endfor %}
{% endfor %}
I noticed that my django code calls my database very often with the exact same queries.
I understand that a db hit is made when I actually need the data to display on a page or to evaluate. However, my template code looks like this:
template:
{% if item.listing %}
{{ item.name }} text <strong>{{ item.listing|lowestprice }}</strong> more text
{% else %}
{{ item.name }} even more text
{% endif %}
....
{% for listed_item in item.listing %}
....
{% endfor %}
custom filter:
def lowestprice(value):
try:
val = unicode(value[0].price) + unicode(value[0].symbol)
return val
except:
return "not available"
This code hits my db three times. First on template {% if .. %} second on my custom filter, third on the {% for %} loop.
listing is a method of my models class which is returning a raw SQL queryset with some very expensive joins.
def listing(self):
return Universe.objects.raw("ONE HELL OF A QUERY")
How can I reduce my code to hit the db only once?
Edit: Using with works, but is it possible to avoid db hits on custom filters?
You should use with to do the expensive query once and store it the context.
{% with item.listing as item_listing %}
{% if item_listing %} ... {% endif %} ... etc ...
{% endwith %}
Given is a model called "comment" with a foreign key relationship to a model called "task".
{% for task in tasks %}
{% for comment in task.comment_set.all %}
{{ comment }}
{% endfor %}
...
What is the best way to limit this to 5 comments like:
Entry.objects.all()[:5]
{% for task in tasks %}
{% for comment in task.comment_set.all|slice:"5" %}
{{ comment }}
{% endfor %}
{% endfor %}
You don't. You should not do "real work" in a template, this breaks the MVC pattern.
Do the real work in the view, and pass the data to the template (using the context dictionary).
def handle_comments(request):
tasks = Task.objects.all()
comments = {}
for task in tasks:
comments[task] = task.comment_set.all()[:5]
return render_to_response('commenting.html', {'comments': comments})
You can then iterate over the comments in your template:
{% for task, task_comments in comments.items %}{{ task }}{% endfor %}