Django Widget Media doesn't work - django

I need a widget, which should only display a block, because i will add functionality with jQuery. I am trying to include the javascript and stylesheet trough the "Media" class of Widget and it doesn't work for me.
Here is the code:
class StarsWidget(Widget):
"""
Widget with stars for rating
"""
class Media:
js = (
settings.MEDIA_URL + 'js/rating.js',
)
css = {
'screen': (
settings.MEDIA_URL + 'css/rating.css',
)
}
def render(self, name, value, attrs=None):
if value is None: value = ''
attrs = {'id':'ratingX', 'class':'rating'}
final_attrs = self.build_attrs(attrs, name=name)
if value != '':
# Only add the 'value' attribute if a value is non-empty.
final_attrs['value'] = force_unicode(value)
return mark_safe(u'<div %s ></div>' % flatatt(final_attrs))
Any suggestions or help will be appreciated

Are you actually including the form media in your template anywhere?
{% block extrahead %}
{{ form.media }}
{% endblock %}

Paths in "class Media" are automatically prepended with settings.MEDIA_URL. So try like this:
class Media:
js = ('js/rating.js',)
css = {'screen': ('css/rating.css',),}
If it will not work, I suggest using FireBug or something like it and checking if browser is able to load css and javascript.
Based on comment:
It appears, that you are not loading your form media at all. Try adding in the template:
{{ my_form.media }}
in {% block subheader %} (or wherever you are loading scripts and css), where "my_form" is the name of your form instance, created in the view.

Minor optimization: You don't need to prepend settings.MEDIA_URL to your paths, it's done automatically when it's printed out.

Related

Custom render RichTextBlock to remove <div class="rich-text">

I'm sure the answer is right there and I'm not seeing it. How can I render a RichTextBlock to remove the wrapping <div class="rich-text">?
{% include_block block %} and {{ block.value }} both give the wrapping div.
Unfortunately this is hard-coded and can't currently be overridden - see https://github.com/wagtail/wagtail/issues/1214.
I solved this by creating a custom template tag
In your project create a file in your templatetags directory (e.g. templatetags/wagtailcustom_tags.py) with content along the following.
from django import template
from django.utils.safestring import mark_safe
from wagtail.core.rich_text import RichText, expand_db_html
register = template.Library()
#register.filter
def richtext_withclasses(value, classes):
if isinstance(value, RichText):
html = expand_db_html(value.source)
elif isinstance(value, str):
html = expand_db_html(value)
elif value is None:
html = ""
else:
raise TypeError(
"'richtext_withclasses' template filter received an invalid value; expected string, got {}.".format(
type(value)
)
)
return mark_safe('<div class="' + classes + '">' + html + "</div>")
Then in your templates load the template tag
{% load wagtailcustom_tags %}
and render richtext fields with the custom classes (or no classes at all)
{{ myfield | richtext_withclasses:"my custom class" }}

How can I use django-jfu with a ImageField and a FK?

I'm trying to use django-jfu to multiupload images, but I have a problem. I want to handle a foreign key dynamically (via url or something), but I can't think of anything.
I have the following models:
class Event(models.Model):
name = models.CharField(max_length=128)
class Picture(models.Model):
event = models.ForeignKey(Event)
image = models.ImageField(upload_to='media')
According to django-jfu, you have to specify a "upload" view to call from the template via template tag. This is my upload view:
#require_POST
def upload(request):
event = Event.objects.get(id=26)
file = upload_receive(request)
instance = Picture(image = file, event = event)
print instance
instance.save()
basename = os.path.basename(instance.image.path)
file_dict = {
'name' : basename,
'size' : file.size,
'url': settings.MEDIA_URL + basename,
'thumbnailUrl': settings.MEDIA_URL + basename,
'deleteUrl': reverse('jfu_delete', kwargs = { 'pk': instance.pk }),
'deleteType': 'POST',
}
return UploadResponse(request, file_dict)
Right now, as a test, it only saves pictures to event with id=26, but how can I handle it dynamically? This is the view and template where I'm calling the template tag:
view
def add_pictures_to_event(request, event_id):
return render(request, 'add_pictures_to_event.html')
template
{% extends 'base.html' %}
{% load staticfiles %}
{% load jfutags %}
{% block body %}
<div class="container">
<h2>Photo upload</h2>
{% jfu %}
</div>
{% endblock %}
As you can see, the view add_pictures_to_event, gets the request and the id of the event, but I cant seem to pass it to the upload view.
Any help would be appreciated.
I had the same question. I looked at different django versions of jQuery File Upload but stuck with Alem's jfu but with the changes from Thomas Willson to make it work in 1.9. My solution might not be the best but I could not find an other way.
I assume you already created an event and then add images to it.
media_upload_form.html is in my projects static directory. I used the UPLOAD_FORM_EXTRA block to add a hidden formfield with the current event_id:
{% block UPLOAD_FORM_EXTRA %}
<input type="hidden" name="currentevent" value="{{instance.pk}}">
{% endblock %}
I assume you have the view from the docs. I changed in the beginning of the uploadview:
file = upload_receive( request )
event_instance = get_object_or_404(Event, id=request.POST['currentevent'])
instance = Picture( file = file, event=event_instance)
instance.save()
It is probably against all django rules but it works. If anyone has a better solution I like to know too. FormSets maybe?

How to use django-compressor to compress form media offline

A Django template (containing a form with media) that includes a snippet like the one below would throw an error when using django-compressor with COMPRESS_OFFLINE=True, because form is not available when offline compression is executed:
# Template snippet
{% compress js %}
{{ form.media.js }}
{% endcompress %}
Generally speaking, django-compressor provides the COMPRESS_OFFLINE_CONTEXT setting to handle similar situations. However, if a site contains many such forms or widgets with media, this solution isn't ideal.
For example, currently, I do something like this in settings.py (for each widget's media):
# settings.py
...
from my_app1.widgets import Widget1
from my_app1.widgets import Widget2
from my_app1.widgets import Widget3
...
widgets = {
'my_widget1': Widget1(),
'my_widget2': Widget2(),
'my_widget3': Widget3(),
...
}
for name, widget in widgets.items():
COMPRESS_OFFLINE_CONTEXT['{}_css'.format(name)] = widget.media['css']
COMPRESS_OFFLINE_CONTEXT['{}_js'.format(name)] = widget.media['js']
And then in templates, I do this:
{% compress js %}
{{ my_widget1_js }}
{% endcompress %}
Is there a way to handle this situation in a manner that more closely resembles Django's {{ form.media }} method, or perhaps without needing to enumerate the specific media to every widget or every form (containing media) in the site?
You can simplify your settings by using some custom class with an __getattr__ method. That way if you will pass that object into template and try to call
{{ obj.my_widget1_js }}
logic inside __getattr__ can search for specified widget in your project and return it's media.
Example of class that will auto-discover each widget:
class WidgetImporter(object):
def __getattr__(self, name):
path = name.split('__') # this will split path on double underscore, so you can define submodule here
path = [(node, "".join(part.capitalize() for part in node.split('_'))) for node in path] # this will convert underscore_names to CamelCase names.
# determining for each module if it's name is CamelCased or underscored
real_path = []
for underscored, cameled in path:
try:
__import__(".".join(real_path + [underscored])) # first trying to import umderscored module
except ImportError:
try:
__import__(".".join(real_path + [cameled])) # now try with cameled
except ImportError:
return "" # or raise some exception here if you like
else:
real_path.append(cameled)
else:
real_path.append(underscored)
last_node = real_path[len(real_path) - 1]
return getattr(__import__(".".join(real_path), fromlist=[last_node]), last_node)() # returning actual class instance
That way you can use it inside your settings.py file:
COMPRESS_OFFLINE_CONTEXT = {
'widgets': WidgetImporter(),
}
and use in your template:
{{ widgets.my_app1__widgets__widget1.media.css }}
Class will try to resolve my_app1__widgets__widget1 to actual path to your class and will try to import it. If it succeeds, it's media['css'] will be printed. It's not 100% optimal code and 100% safe (there can be some vulnerabilities if someone has access to your templates), but it will do the job.

Django: Figure out which item in a menu that has been selected

I'm sure I've seen this question on Stack Overflow before, but I couldn't find it by my life, so here goes nothing.
I have a normal Django menu which uses the {% url %} tag and static names for the menu items. Now I want to have a different style for the menu item which has been selected. But the menu is being rendered in the base template, so how do I figure out which menu item it is?
You could surely do this with some ugly template code, but a better more globally known way is to use a CSS selector. This lets CSS do all of the work automatically for you.
Here's how it works:
You simply put an id in your body depending on which page you are on.
Then in css you do something like this:
#section-aboutme #nav-aboutme,
#section-contact #nav-contact
/* ... put one of these per body/menu item ... */
{
font-color: red;
}
You put the nav-aboutme, and nav-contact ids on each of your menu items.
The style will automatically be selected by CSS depending on which body id they are inside of.
I normally do it the way Brian suggested, but to accommodate for a template which a designer gave me which used the more common class="selected" method, I wrote a {% nav %} template tag.
Your HTML navigation template will look something like:
{% block nav %}
<ul class="nav">
<li{% if nav.home %} class="selected"{% endif %}>Home</li>
<li{% if nav.about %} class="selected"{% endif %}>About</li>
</ul>
{% endblock %}
To set the navigation in a child template, do:
{% include "base.html" %}
{% load nav %}
{% block nav %}
{% nav "about" %}
{{ block.super }}
{% endblock %}
How about a custom tag which you use to generate your nav item?
The following takes the name of the url for which a nav item should be generated and the text it should display. It generates a li tag with a class of "selected" if the named url's path is the same as the current url (requires 'django.core.context_processors.request' in your TEMPLATE_CONTEXT_PROCESSORS). Within the li, it generates an a tag with the path of the url specified by the url_name. It has the contents specified by contents.
Obviously, this could be tweaked to generate different markup for the nav item, as required.
The rest can be done using CSS.
Advantages:
Easy to use
Little code required
DRY
Could be made to be more flexible
Disadvantages:
Requires 'django.core.context_processors.request'
Requires urls to be named e.g. urlpatterns = patterns('django.views.generic.simple',
...
(r'^$', 'direct_to_template', {'template': 'index.html'}, 'index'),
...
). This could potentially be done differently (e.g. pass in url).
Doesn't cope with pages not exactly equal to the specified and therefore will not apply the selected class to the li when on a page lower in the url heirarchy. For example, if I'm on /products/, it will highlight the nav item directing to /products/. If I'm on /products/myProduct/, it will not highlight the /products/ link. This could be coded around, but it would force people to use sensible urls. For example, change the additionalAttrs assignment to additionalAttrs = ' class=selected' if (context['request'].path.startswith(path) and path != '/') or (context['request'].path == path) else ''.
Code:
from django import template
from django.core.urlresolvers import reverse
register = template.Library()
class NavNode(template.Node):
def __init__(self, url_name, contents):
self.url_name = url_name
self.contents = contents
def render(self, context):
path = reverse(self.url_name)
additionalAttrs = ' class=selected' if path == context['request'].path else ''
return '<li'+additionalAttrs+'>'+self.contents+'</li>'
#register.tag
def nav_link(parser, token):
bits = token.split_contents()
if len(bits) == 3:
contents = bits.pop()
url_name = bits.pop()
else:
raise template.TemplateSyntaxError, "%r tag requires a single argument" % bits[0]
if contents[0] == contents[-1] and contents[0] in ('"', "'"):
contents = contents[1:-1]
return NavNode(url_name, contents)
You can pass request.path to your template
from django.shortcuts import render_to_response
from django.template import RequestContext
return render_to_response('templ.html', {'page':request.path}, context_instance=RequestContext(request))
then use an ugly if template tag to add a CSS class to your menu item
Let's say one has an app named "stackoverflow" and inside of that app folder one has a templates folder with a stackoverflow.html file that extends from the base template.
One way to achieve it is by defining a variable in the views.py of ones stackoverflow app, like
def stackoverflow(request):
return render(request,
'stackoverflow/stackoverflow.html',
{'section': 'stackoverflow'})
Then, in the base template
<li {% if section == "stackoverflow" %} class="selected" {% endif %}>
StackOverflow
</li>
Essentially having the variable section allows to figure the section. Note that one needs a space between section and ==... if one doesn't respect that, then one will get a Django Template Error saying
Could not parse the remainder.

How to render form field with information that it is required

Is there any clever way to make django forms render field with asterisks after fields that are required? Or to provide some other clever for to mark required fields? I wouldn't like to have to do it again in a template if I already set a field as required in the form.
As of Django 1.2, if your form has an attribute named required_css_class, it will be added to BoundField.css_classes for required fields. You can then use CSS to style the required parts of the form as desired. A typical use case:
# views.py
class MyForm(django.forms.Form):
required_css_class = 'required'
…
…
/* CSS */
th.required { font-weight: bold; }
…
<!-- HTML -->
<tr>
<th class="{{form.name.css_classes}}">{{form.name.label_tag}}</th>
<td>{{form.name.errors}}{{form.name}}</td>
</tr>
If you use Form.as_table(), Form.as_ul, and Form.as_p, they do this automatically, adding the class to <tr>, <li>, and <p>, respectively.
You also can use a field.field.required property:
{% for field in form %}
{{field.label}} {% if field.field.required %} * {% endif %}
{{field}}
{{field.errors}}
{% endfor %}
The best way for such purposes I have found is to render form's output via an html template. How to do this is described here. By luck, the example puts an asterisk after required fields just like you want.
I use a template tag to render form fields with their labels and errors, plus an asterisk and a CSS class for required fields. There are various snippets available to do it on www.djangosnippets.org
Personny I tried something like this, i.e. overriding the default template tag (this adds a red asterisk in all the admin interface for required not-readonly fields. Then i also defined a 2nd tag for my views that mix inline and block labels. See the code below (copy/paste of Django source code with some modifications):
In settings.py :
from django.forms.util import flatatt
from django.utils.html import conditional_escape
from django.utils.safestring import mark_safe
import django.forms.forms as django_forms
def custom_label_tag(self, contents=None, attrs=None):
"""
Wraps the given contents in a <label>, if the field has an ID attribute.
Does not HTML-escape the contents. If contents aren't given, uses the
field's HTML-escaped label.
If attrs are given, they're used as HTML attributes on the <label> tag.
"""
contents = contents or conditional_escape(self.label)
widget = self.field.widget
id_ = widget.attrs.get('id') or self.auto_id
if id_:
attrs = attrs and flatatt(attrs) or ''
if self.field.required:
label = unicode(contents)
label_suffix = ""
if label[-1] == ":":
label = label[:-1]
label_suffix += ":"
contents = u'<label for="%s"%s>%s<span style="color:red;">*</span>%s</label>' % (widget.id_for_label(id_), attrs, label, label_suffix)
else:
contents = u'<label for="%s"%s>%s</label>' % (widget.id_for_label(id_), attrs, unicode(contents))
return mark_safe(contents)
def custom_inline_label_tag(self, contents=None, attrs=None):
if attrs:
if "class" in attrs.keys():
attrs["class"] += " inline"
else:
attrs["class"] = "inline"
else:
attrs = {"class": "inline"}
return self.label_tag(contents, attrs)
django_forms.BoundField.label_tag = custom_label_tag # override django method
django_forms.BoundField.inline_label_tag = custom_inline_label_tag
In my templates
<p>{{ form.fieldname.errors}}{{ form.fieldname.inline_label_tag }}{{form.fieldname}}</p>
OR
<p>{{ form.fieldname.errors}}{{ form.fieldname.label_tag }}{{form.fieldname}}</p>