I´m trying to use foreign key values in a template.
When I try to show it, I get the value on screen correctly.
{% for x in dataset %}
<p> {{ x.fieldname }}
{% endfor %}
But when I try to use it for comparisons it uses the id, not the value.
{% for x in dataset %}
{% if x.fieldname == "The name I want" %}
<p> {{ x.fieldname }}
{% endif %}
{% endfor %}
I´ve been looking some posts relateing serializers with this, but (in my little knowledge) I understand serializers are to send or receive data from outside the application.
As the is only tu use the values within the application, is there another way to get the actual value for comparisons? Should I use the serializers approach?
Thanks!
I think you assume too much "magic" here. If you fetch the attribute that is related to a ForeignKey, it simply fetches the related instance. Now in case you render such instance, Django will typically fallback on the __str__ of the model instance.
So what you need to do is find out how the __str__ of the model that is referenced works. For example if Model uses the .name attribute to convert it to a string, you can write:
{% if x.fieldname.name == "The name I want" %}
In case it is unknown how it is rendered, you can use the stringformat template filter:
{% if x.fieldname|stringformat:"" == "The name I want" %}
Related
I am using django-widget-tweaks and its render_field. I have an odd situation and I wonder if there is a workaround or a different approach that I should use?
I am using django and allauth (I am not using the social auth part yet). I have the default django user model and I have a "Profile" model that extends the user model. That's all working.
This is a specialized "Membership App". Only adults over 18 should be able to login. Once logged in a person can create "member" one or more "member" records. The logged in person is responsible for payng for memberships but might not be a member themselves; for example, a parent might log in and create member records for youth under 18 while not being a member themselves.
When creating a new member record I need to give the logged in person the opportunity to create a member record for themselves (if they don't already have one). If they chose this option then the logged in person's "Profile" info should auto-fill the new member form. To facilitate this I am capturing and serializing the logged in user's Profile info and am passing it to the CBV MemberCreate method. This method renders the Member Create form using django-widget-tweaks and its render_field method, a la:
{% with field=newMemberForm.first_name %}
{% render_field field class="form-control form-control-sm" %}
{% endwith %}
I want to create a data-loggedindata= attribute that uses the field.name value as the "member name" of the logged in person's profile. SOmething like:
{% with field=newMemberForm.first_name %}
{% render_field field class="form-control form-control-sm" data-loggedindata=LoggedInProfile.{{field.name}} %}
{% endwith %}
But django-widget-tweaks doesn't seem to understand that and I am not wise enough in the world of django to know a workaround.
I can hear someone typing: "but you know the field name from the {% with ... %} construct". Yes, that is true but the Member form has a lot of fields so I wrapped the render_field part in a small html file that I include. So the reall segment above might look like:
{% with field=profileForm.first_name %}
<div class="form-group col col-3">
{% include "Members/template_includes/field_render.html" %}
</div>
{% endwith %}
And the included file has the render_field in it. Inside that included html file I have no idea of the name of the field.
ideas?
Edit
I have tried Pankaj's suggestion below but
{% render_field field|attr:"data-loggedindata=LoggedInProfile.{{field.name}}" %}
does not appear to interpolate the object LoggedInProfile or the {{field.name}} value. What I get is the un-interpolated string "LoggedInProfile.{{field.name}}".
I have tried:
{% render_field field|attr:"data-loggedindata:getattr(LoggedInProfile, field.name" %}
but that is not interpolated either. Is there a way in a Django template and/or widget-tweaks to programatically get the value of an object attribute?
Edit 2
I decided to go another way. I am still using widget-tweaks but I am not trying to use render_field in this way anymore. I am serializing the data that would be placed in the data- elements and placing the JSON version in a hidden form field. I am letting javascript deal with it now.
If you want to add attribute in field with django-widget-tweaks you can simply use attr for that, in your case it would be like -
{% with field=newMemberForm.first_name %}
{% render_field field|add_class:"form-control form-control-sm"|attr:"data-loggedindata=LoggedInProfile.{{field.name}}" %}
{% endwith %}
Still have any doubts let me know
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 %}
In my django templates i have a list of objects which is rendered as follows:
<li class="keys">
{% for key in job.key_list|slice:":2" %}
{% if not forloop.last %}
{{ key }},
{% else %}
{{ key }}
{% endif %}
{% endfor %}
</li>
This outputs the list as:
some_key, some_key_two
I want to truncate the number of characters to 20 but on the whole list. So that it renders something like:
some_key, some_key_t...
I am aware about the truncatechars and truncatewords filters available in django but they work on a string variable within the template.
How do i go about implementing this functionality ?
Wow, that's a strange requirement. You would have to implement this as a template tag or custom filter that takes a list and transforms it.
#register.filter(name='truncatinator')
def truncatinator(value, arg):
strings = ",".join(value)
if len(strings) >= arg:
part = strings[0:19] + "..."
return part.split(',')
and use it like this {% for object in job.key_list|truncatinator:"20" %}
What you will notice though is that you will loop over a string list here instead of your objects which will give you this disadvantage: You won't have access to your .id.
This could be modified though as well.
I would do this with Javascript instead but I don't think that Django should be responsible for this overall.
I'm using django-haystack for a search page on my site, and I want to order all the results by their content type. Is there a way I can do that?
To make it simpler, suppose I have a single application and several classes.
Thanks in advance
Not sure what you mean by content type, but if you are talking about group by models, I have this working
{% with page.object_list as results %}
{% regroup results|dictsort:"verbose_name_plural" by verbose_name_plural as grouped_objects %}
{% for ct in grouped_objects %}
{{ ct.grouper }}
{% for result in ct.list %}
<p>
{{ result.object }}
</p>
{% endfor %}
{% empty %}
<p>No results found.</p>
{% endfor %}
{% endwith %}
from How to order search results by Model:
You can do
SearchQuerySet().order_by('django_ct').
As a warning, this throws out
relevancy. The only way to keep
relevancy & group by model is either
to run many queries (one per model -
usually performant thanks to query
caching) or to run the query and
post-process the results, regrouping
them as you go.
from searchindex api:
Haystack reserves the following field
names for internal use: id, django_ct,
django_id & content. The name & type
names used to be reserved but no
longer are.
You can override these field names
using the HAYSTACK_ID_FIELD,
HAYSTACK_DJANGO_CT_FIELD &
HAYSTACK_DJANGO_ID_FIELD if needed.
I'm trying to build a blog app and the problem is when I use tag 'truncatewords_html' in my template to truncate posts longer than specified number of words, I need to link to complete post by some title like 'read more...' after truncation. So I should know that the post was truncated or not.
P.S.: Is this a pythonic way to solve the problem?
{% ifequal post.body|length post.body|truncatewords_html:max_words|length %}
{{ post.body|safe }}
{% else %}
{{ post.body|truncatewords_html:max_words|safe }}read more
{% endifequal %}
This is pretty convoluted but django has some weird corners. Basically I figure if the string length is the same if you truncate at x and x+1 words then the string has not been truncated...
{% ifnotequal post.body|truncatewords_html:30|length post.body|truncatewords_html:31|length %}
read more...
{% endifnotequal %}
You could write a custom template tag (see django docs), or manually check in the template, whether the content you want to display exceeds the given length via length builtin filter.
It comes down to personal preference, but for my taste you're doing way too much work in the template. I would create a method on the Post model, read_more_needed() perhaps, which returns True or False depending on the length of the text. eg:
def read_more_needed(self):
from django.utils.text import truncate_html_words
return not truncate_html_words(self.body,30)==truncate_html_words(self.body,31)
Then your template would read:
{% if post.read_more_needed %}
{{ post.body|truncatewords_html:30|safe }}read more
{% else %}
{{ post.body|safe }}
{% endif %}
Check out http://code.djangoproject.com/ticket/6799
This patch provides a method to replace the default elipses for truncated text.