views:

383

answers:

4

Hi folks,

I am a new Djangoer, and figuring out how to build custom widget, my problem is cannot get the MEDIA_URL in my widget's template, while the form use MySelectWidget able to get the MEDIA_URL itself.

#
#plus_sign.html
#
<a href="" class="" id="id_{{ field }}">
    <img src="{{ MEDIA_URL }}images/plus_sign.gif" width="10" height="10" alt="Add"/>
</a>

*^ cannot load the {{ MEDIA_URL}} to this widget's template, and therefore I can't load the .gif image properly. :(*

#
#custom_widgets.py
#
from django import forms

class MySelectMultiple(forms.SelectMultiple):

    def render(self, name, *args, **kwargs):
        html = super(MySelectMultiple, self).render(name, *args, **kwargs)
        plus = render_to_string("plus_sign.html", {'field': name})
        return html+plus

#
#forms.py
#
from django import forms
from myapp.custom_widgets.py import MySelectMultiple

class MyForm(forms.ModelForm):
contacts = forms.ModelMultipleChoiceField(Contact.objects, required=False, widget=MySelectMultiple)

#
#views.py
#

def AddContacts(request):
    if request.method == 'POST':
        form = MyForm(request.POST)

        if form.is_valid():
            cd = form.cleaned_data
            new = form.save()
            return HttpResponseRedirect('/addedContact/')
    else:
        form = MyForm()

    return render_to_response('shop/my_form.html', {'form': form}, context_instance=RequestContext(request))


#
#my_form.html
#
{% extends "base.html" %}

{% block content %}
   {{ form.contacts }}
{% endblock %}

Please let me know how can I load the widget's image properly. Thank you so much for all responses.

A: 

Make sure the context processor is being loaded in settings.py

TEMPLATE_CONTEXT_PROCESSORS=(
    ...other processors,
    "django.core.context_processors.media",
)

It is loaded by default if you don't specify TEMPLATE_CONTEXT_PROCESSORS, but if specified, the above processor must also be included.

http://docs.djangoproject.com/en/dev/ref/settings/#template-context-processors

czarchaic
Hi czarchaic, thanks for your reply. I have added this in the settings.py:TEMPLATE_CONTEXT_PROCESSORS = ( #...other processors, 'django.core.context_processors.media', )but still doesn't work :(
Eric
to be precise, if I put the {{ MEDIA_URL}} in my_form.html, it can get the media url, but the widget DOESN"T
Eric
A: 

Context processors only get applied when you use a RequestContext.

Your render method should be something like:

from django.template import RequestContext

def render(self, name, *args, **kwargs):
    html = super(MySelectMultiple, self).render(name, *args, **kwargs)
    context = RequestContext({'field': name})
    plus = render_to_string("plus_sign.html", context)
    return html + plus

And, as was mentioned by @czarchaic, make sure the media context processor is in TEMPLATE_CONTEXT_PROCESSORS (it should be by default).

Docs link.

Seth
There's a problem with this approach, as you'd need to send the request to the widget somehow as RequestContext takes the request as its first parameter.
Jj
thank you so much @SethI thought the widget will automatically get the RequestContext of the form that use it before without explicit using the RequestContext to warp the variables that pass back to the View.This works. Thank you so much!
Eric
But seems I can't access the {{ field }} in the widget's template now<a><img src="{{ MEDIA_URL }}images/shops/icon_addlink.gif" width="10" height="10" alt="{{ field }}"/></a>
Eric
A: 

Actually the correct way to do this is using Widget Media.

When defining your widget, you should define a Media inner class in which you should include a CSS file in order to style your widget. In this case make the <a> tag not to display text and have a plus sign background image.

class MyWidget(TexInput):
  ...
  class Media:
    css = {
      'all': ('my_widget.css',)
    }

If you really need to include the MEDIA_URL inside your rendered widget, I'd recommmend to import it directly from django.conf.settings and include settings.MEDIA_URL in your rendering context.

from django.conf import settings

class MyWidget(TextInput):
  ...
  def render(self):
    return render_to_string('my_widget.html', {
      'MEDIA_URL': settings.MEDIA_URL,
      ...
    })
Jj
thank you so much @Jj
Eric
So doesn't that mean we must use CSS even for the image source to specific the image path location?
Eric
A: 

I think we can do in this way, to pass the RequestContext, in order to access the MEDIA_URL without making another variable, and passing other variables at the 2nd parameter of the render_to_string method.

If we use:

context = RequestContext({'field': name})

The {{ field }} in the widget's template is empty and not able to access.

Here is the block which can access the MEDIA_URL as well as the {{ field }}. However, I agree using the inner Media class for complex javascript and CSS setting. However, for a simple image src path, I think this will do.

def render(self, name, *args, **kwargs):
        html = super(SelectMultipleWithModalDialog, self).render(name, *args, **kwargs)        
        **context = RequestContext({})
        popup_plus = render_to_string("widgets/modal_dialog_plus_sign.html", {'field': name}, context_instance=context)**        
        return html + popup_plus

Please correct me if this is not the good way of doing it. Thanks for all participants of this thread.

Eric