SelectDateWidget - how get to each subfield separately? - django

In project there is used SelectDateWidget and to render it in template it only need to write form.date_of_sth, but it renders all widgets (selects) in one. I would like to render each one separately. Is there any way to do it?

In Django 1.11:
Import the widget that you want to modify. Your choices can be found here: https://docs.djangoproject.com/en/1.11/ref/forms/widgets/#built-in-widgets
Create a subclass and specify the template name.
# app/widgets.py
from django.forms.widgets import DefaultWidget
class CustomWidget(DefaultWidget):
template_name = 'app/widget.html'
Create your template. This is copied exactly from django/forms/widgets/multiwidget.html but you can put anything you want here. You can also reference other existing widget templates for inspiration. Your choice can be found here: https://github.com/django/django/tree/master/django/forms/templates/django/forms/widgets
# app/templates/app/widget.html
{% spaceless %}
{% for widget in widget.subwidgets %}
{% include widget.template_name %}
{% endfor %}
{% endspaceless %}
Import your CustomWidget and add it to a field in your form.
# app/forms.py
from django import forms
from .widgets import CustomWidget
class MyForm(forms.Form):
my_field = forms.ExampleField(widget=CustomWidget())
Finally, in your template, render the main field and it will reference app/templates/app/widget.html to render each subfield manually based on the template you created.

Related

Is there a way to pass model attribute into another attribute?

I'm using {% autoescape off %} to render html that I add through admin page. I want to get another variable of the model.
post.html
{% autoescape off %}
{{ post.content }}
{% endautoescape %}
Is it possible to pass another attribute of the same model into post.content? Something like that
post.content
<img src="{{ post.main_image.url }}">
Yup. Assuming there is a post, and it has a main_image, which has a url, there shouldn't be any problem. You may want to check in the template if you are not sure yourself first though. So to be safer, you should do:
{% if post and post.main_image %}
<img src="{{ post.main_image.url }}">
{% endif %}
Ok, I've finally made it. My goal was to create CMS-ish admin page of a model, where I could add raw html, django tags and variables directly to the content attribute along with other attributes like titles, categories, images and so on. I've managed to do it by using and customizing django-dbtemplates package.
pip install django-dbtemplates
First, fork template model from dbtemplates and add your model as a foreign key
blog/models.py
from dbtemplates.models import Template as CoreTemplate
class Template(CoreTemplate):
post = models.ForeignKey(Post, on_delete=models.CASCADE)
Then just customize your admin.py to show template field as an attribute
blog/admin.py
from .models import Post, Template
class TemplateInline(admin.TabularInline):
model = Template
extra = 0
class PostAdmin(admin.ModelAdmin):
inlines = [TemplateInline, ]
Optional
You can generate html names of you template based on your model slug by modifying save function of the Template class
blog/models.py
from dbtemplates.models import Template as CoreTemplate
from dbtemplates.conf import settings
class Template(CoreTemplate):
post = models.ForeignKey(Post, on_delete=models.CASCADE)
def save(self, *args, **kwargs):
self.last_changed = now()
slug = self.post.slug
self.name = f'{slug}-content.html'
if settings.DBTEMPLATES_AUTO_POPULATE_CONTENT and not self.content:
self.populate()
super(Template, self).save(*args, **kwargs)
Then in your html you can render this template with context manager
post.html
{% with post.slug|add:'-content.html' as content %}
{% include content %}
{% endwith %}
Now in your admin settings you can have just one big content field from basic Template class
blog/admin.py
from .models import Template
from django.forms import Textarea
class TemplateInline(admin.TabularInline):
model = Template
extra = 0
fields = ('content',)
formfield_overrides = {
models.TextField: {'widget': Textarea(attrs={'rows': 40, 'cols': 150})},
}
To remove default dbtemplates Template class from your admin panel just unregister it in your admin settings
blog/admin.py
from dbtemplates.admin import Template as CoreTemplate
admin.site.unregister(CoreTemplate)

'My_Model' object is not iterable using customtag in django

I am new to Django and I am trying to make my data accessible to templates in different apps by creating custom tags in Django.
my model.py
from django.db import models
class my_Model(models.Model):
name = models.CharField(max_length=20)
age = models.CharField(max_length=20)
my custom tag file templatetag/custom_tag.py(why I did this is to make my data accessible to templates in different apps)
from django import template
from model_file.models import my_Model
register = template.Library()
#register.simple_tag
def get_custom_tag_fn():
return my_Model.objects.order_by('-pk')[0]
my html file
{% load custom_tag %}
{% get_custom_tag_fn as ct %}
{% for item in ct %}
<p> {{ item }} </p>
{% endfor %}
I am getting the error 'My_Model' object is not iterable. Any thought about how to solve this.
The problem is here:
return my_Model.objects.order_by('-pk')[0]
Model objects.order_by(...) returns queryset, alike to the list it`s a collection, so with [0] index you take the first object of that collection which of course is not iterable (it's just a single object). So, after that, when you trying to iterate:
{% for item in ct %}
...
you`re catching this error.

django-cms getting the page context in an application hook

Consider this cms_app.py
from django.utils.translation import ugettext_lazy as _
from cms.app_base import CMSApp
from cms.apphook_pool import apphook_pool
class FooHook(CMSApp):
name = _("FooHook Plugin")
urls = ["foo.urls"]
apphook_pool.register(FooHook)
The foo app, has a views model which contains to default django views, ListView and DetailView.. These have their default templates, inheriting from a base.html, these are foo_list.html and foo_detail.html..
The documentation is completely unclear how to get, for example the cms page's sidebar content or page context variable at all, within those templates..
Feincms has the {% fragment %} template tag for this purpose, how can one achieve this in django-cms?
To access the page you can use {{ request.current_page }}
To use the plugin system in your templates use {% static_placeholder my_name %} instead of the {% placeholder %} tags.
It is always preferable to use the static_placeholders in apphooks as you do not know what template and what placeholders the page actually has.

field's verbose_name in templates

Suppose I have a model:
from django.db import models
class Test(models.Model):
name=models.CharField(max_length=255, verbose_name=u'custom name')
How do I get my model's field's verbose name in templates? The following doesn't work:
{{ test_instance.name.verbose_name }}
I would very much appreciate the solution, something on lines as we do when using forms, using label attribute in template:
{{ form_field.label }}
You can use following python code for this
Test._meta.get_field("name").verbose_name.title()
If you want to use this in template then it will be best to register template tag for this. Create a templatetags folder inside your app containing two files (__init__.py and verbose_names.py).Put following code in verbose_names.py:
from django import template
register = template.Library()
#register.simple_tag
def get_verbose_field_name(instance, field_name):
"""
Returns verbose_name for a field.
"""
return instance._meta.get_field(field_name).verbose_name.title()
Now you can use this template tag in your template after loading the library like this:
{% load verbose_names %}
{% get_verbose_field_name test_instance "name" %}
You can read about Custom template tags in official django documentation.
The method in the accepted answer is awesome!
And maybe you'll like this if you want to generate a field list.
Adding an iterable to the class Test makes it convenient to list fields' verbose name and value.
Model
class Test(models.Model):
...
def __iter__(self):
for field in self._meta.fields:
yield (field.verbose_name, field.value_to_string(self))
Template
{% for field, val in test_instance %}
<div>
<label>{{ field }}:</label>
<p>{{ val }}</p>
</div>
{% endfor %}
based on this answer https://stackoverflow.com/a/14498938 .in Django Model i added
class Meta:
app_name = 'myapp'
in listview i have
from django.core import serializers
context['data'] = serializers.serialize( "python", self.get_queryset() )
inside mylist.html i have
{% for field, value in data.0.fields.items %}
<th style="text-align:center;">{% get_verbose_field_name data.0.model field %}</th>
{% endfor %}
in filter:
from django import template
register = template.Library()
from .models import Mymodel
#register.simple_tag
def get_verbose_field_name(instance, field_name):
"""
Returns verbose_name for a field.
"""
myinstance = eval(instance.split('.')[1].title())
return myinstance._meta.get_field(field_name).verbose_name.title()
instance in the abbove filter for the specific example is myapp.mymodel i evalute instance into model object and the i return field verbose name
it works in django 1.9
It's probably too late for an answer but I had the same issue until I realised that I caused the problem by overriding the fields in the form.py (self.fields['fieldname'] = ..). If you do that you also need to set a label otherwise it uses a label derived from the fieldname.
Hope this quick reply makes sense.

Form labels not rendering with Django & WTForms

I'm trying to use WTForms with Django & a MongoEngine/MongoDB database backend. The forms are outputting properly, but I can't for the life of me get the labels to show up.
Here is my template code:
{% load wtforms %}
<form>
{% for f in form %}
{{ f.label }}: {% form_field f %}<br/>
{% endfor %}
</form>
This is what I am passing in the view:
form = StrandForm()
return render_to_response('create_strand.html', locals(), context_instance = RequestContext(request))
The StrandForm class I have tried both creating from the WTForm mongoengine extension's model_form class, and from WTForm's Form class. The label exists in the view, I can print it to the console and it shows the rendered form label, but somehow it gets lost when transferring to the template. Am I doing something wrong?
Django 1.4 has a new feature: do_not_call_in_templates attribute.
If you set it on wtforms.Field class, every child class inherits and all fields will work fine in django templates.
import wtforms
wtforms.Field.do_not_call_in_templates = True
Now following code works as expected:
{% load wtforms %}
{{ f.label }}: {% form_field f %}
I encountered the same problem today. It has to do with the way WTForms is programmed so that it will work with many different templating libraries. Django 1.3 will only see f as it's HTML string even though it has other attributes.
In order to fix this you must add a template tag to retrieve the attribute.
Add the following to your projects hierarchy:
templatetags
templatetags / init.py
templatetags / templatetags
templatetags / templatetags / init.py
templatetags / templatetags / getattribute.py
Then in your settings.py file, add the following line to INSTALLED_APPS
'templatetags',
Open up getattribute.py and paste the following code:
from django import template
from django.conf import settings
register = template.Library()
#register.tag
def getattribute(parser, token):
try:
tag_name, tag_object, tag_function = token.split_contents()
except ValueError:
raise template.TemplateSyntaxError("%r tag requires two arguments" % token.contents.split()[0])
return getattrNode(tag_object, tag_function)
class getattrNode(template.Node):
def __init__(self, tag_object, tag_function):
self.tag_object = tag_object
self.tag_function = tag_function
def render(self, context):
return getattr(context[self.tag_object], self.tag_function)()
This will allow you to use the follow code whenever you're inside a template and need an attribute that won't show up:
{% load getattribute %}
{% getattribute OBJECT ATTRIBUTE %}
In your case:
{% getattribute f label %}
Hope that helped!