django-imagekit - better way of showing a default image? - django

I'm using django-imagekit to resize my user avatars and right now to display a default avatar (if the user didn't upload his/her avatar) I do this:
views.py
try:
usr_avatar = UsrAvatar.objects.get(user=request.user.id)
except UsrAvatar.DoesNotExist:
usr_avatar = UsrAvatar.objects.get(id='0')
template.html
<img src="{{ usr_avatar.avatar_image.url }}" >
This works fine but every time a user didn't upload his/her avatar I'm hitting the database for the default avatar image.
Is there a way to eliminate hitting the database when the user doesn't have an avatar image loaded by somehow attributing the default image link to usr_avatar or just doing something in the template.html? Thank you!

Apt username given your question!
You could create a context processor that provides the default avatar to every template and simply make sure that the context processor caches the image
settings.py
TEMPLATE_CONTEXT_PROCESSORS = (
...
'myapp.context_processors.default_avatar',
...
)
myapp/context_processors.py
from django.core.cache import cache
def default_avatar(request):
default_avatar = cache.get('default_avatar', False)
if not default_avatar:
default_avatar = UsrAvatar.object.get(id='0')
return {
'default_avatar' : default_avatar
}
Now the template variable 'default_avatar' is available in every template:
{% if usr_avatar %}
{{ usr_avatar }}
{% else %}
{{ default_avatar }}
{% endif %}
Alternatively just use the cache in your original query:
try:
usr_avatar = UsrAvatar.objects.get(user=request.user.id)
except UsrAvatar.DoesNotExist:
usr_avatar = cache.get('default_avatar', False)
if not usr_avatar:
usr_avatar = UsrAvatar.objects.get(id='0')
But Finally, it might be even better to avoid keeping the default avatar in the database at all and instead just write a context processor like above but instead of getting the default avatar from the DB, just have a static url to the image
from django.conf import settings
def default_avatar(request):
return {
'default_avatar' : '%simages/default_avatar.jpg' % settings.STATIC_URL
}

Related

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 retrieve absolute urls to thumbnails generated via django-filer easy-thumbnails

I am using following template tags to display thumbnails in my templates
{% load thumbnail %}
{% thumbnail obj.image 250x250 crop %}
thumbnail template tag returns relative urls to thumbnail image files as expected. But I would like it to return absolute urls. Normally easy-thumbnails has THUMBNAIL_MEDIA_URL = '' setting which allows thumbnail's storage to build absolute urls but it does not work with django-filer.
Is there any other way to achieve what I want?
You can extract the thumbnail properties using as
{% thumbnail obj.image 250x250 as thumb %}
{{thumb.url}}
See http://easy-thumbnails.readthedocs.org/en/latest/usage/#thumbnail-tag
EDIT:
If by "absolute" you mean including the website, I would recommend doing the logic elsewhere.
Considering image to be a FilerImageField, create a property in the models.py. Example:
from django.contrib.sites.models import Site
from easy_thumbnails.files import get_thumbnailer
#property
def thumbnail_absolute_url(self):
if self.image:
thumbnailer_options = {'size': (250, 250), 'crop': True}
thumb = get_thumbnailer(self.image).get_thumbnail(thumbnailer_options)
thumb_url = thumb.url
site = Site.objects.get_current()
return site.domain + thumb_url
return None
See https://github.com/SmileyChris/easy-thumbnails#manually-specifying-size--options

Rackspace Cloudfiles and Django Cumulus

From the past 2 days i have literally lost my patience trying to make Cloudfiles work for my project(using cumulus). Here are some of the issues:
1.) Sometimes when i upload any photo using admin(creating a model and registering with admin)... the photo looks like its uploaded but when i try to either access it using a view function by Photo.objects.all() or even going to the cloudfiles control panel...the image simply doesnt open up. I get a resource not found. I check and double check if the region(chicago is default for me) settings is screwing with me....but i don't think so.
2.) I have used collectstatic method to successfully collect all static files in a container and i am able to successfully serve them. infact when i click the link(say for example) - http://ed770b871265201bf471-14f03984d90730040890dd30a2d85248.r68.cf2.rackcdn.com/admin/css/base.css
I am able to see the results and i am sure u can see it too.
But when i am trying to use them by STATIC_URL in my templates - The admin pages don't have their css working but my login/home pages are perfectly being rendered with my styles.
Here are my settings file/my view functions and anything that is important -
STATIC_ROOT = ''
STATIC_URL = 'http://ed770b871265201bf471-14f03984d90730040890dd30a2d85248.r68.cf2.rackcdn.com/'
STATICFILES_DIRS = (
os.path.join(PROJECT_DIR,'static'),
)
CUMULUS = {
'USERNAME': '***',
'API_KEY': '****',
'CONTAINER': 'photos',
'STATIC_CONTAINER':'static',
'SERVICENET': False, # whether to use rackspace's internal private network
'FILTER_LIST': [],
'TIMEOUT' : 60
}
DEFAULT_FILE_STORAGE = 'cumulus.storage.CloudFilesStorage'
STATICFILES_STORAGE = 'cumulus.storage.CloudFilesStaticStorage'
The model file part
class Photo(models.Model):
username = models.ForeignKey(User)
image = models.ImageField(upload_to='photos')
alt_text = models.CharField(max_length=255)
admin.site.register(Photo)
This is the view function as you requested kyle.
def profile_detail(request):
if request.user.is_authenticated():
username = request.user.get_username()
# userid = User.objects.get(username=username).values('__id')
userdetails = User.objects.filter(username=username)
photo = Photo.objects.get(username=request.user.id)
return render_to_response('profile_detail.html',{'userdetails':userdetails,'username':username,'photo':photo},
context_instance=RequestContext(request))
and the template for profile_detail -
{% extends 'profile.html' %}
{% load bootstrap_toolkit %}
{% block content %}
<img src="{{ photo.image.url }}" alt="{{ photo.alt_text }}" />
<br>
<p>{{ user.first_name }}</p>
<p>{{ user.last_name }}</p>
<p>{{ user.email }}</p>
{% endblock %}
I just now checked that i can view the image(No idea how) on the hosted site(production) but still can't do it in my dev environment.
Kyle can you please check if your testaccount has a picture of penguins in the 'MYProfile' page? :) Thanks for looking into it :)
The images are there, but possibly not where you expected them.
Link on your current site:
http://d12df125d01b8a258a3a-8112fdc02f7d385b44f56eb9e899d81c.r88.cf2.rackcdn.com/photos/Penguins.jpg
Where the image/file actually is:
http://d12df125d01b8a258a3a-8112fdc02f7d385b44f56eb9e899d81c.r88.cf2.rackcdn.com/photos%5CPenguins.jpg
The %5C is a \ rather than a /. This makes a difference as these are keys (key being the "path" and value being the file). You may want to check on how these were uploaded, and possibly normalize them to regular slashes (were these uploaded while you were on a Windows machine?).

Django dynamic forms - on-the-fly field population?

I've been scanning through Django documentation, and Google search results, all afternoon and I'm still somewhat stuck in my attempt to create a dynamic form. I'm hoping I just need someone to nudge me in the right direction :-) I'm just starting to learn Django, so I'm still very much a beginner; however, I'm already an intermediate python user.
What I'm trying to do is create a dynamic form, where the user makes a selection from a drop-down menu, and based on that selection another part of the form will automatically update to display results relevant to the currently selected item, but from another database table.
I'll try and use a simplified version of the models from the Django tutorial to better illustrate what I'm trying to do:
# models.py
from django.db import models
class Poll(models.Model):
question = models.CharField(max_length=200)
class Choice(models.Model):
poll = models.ForeignKey(Poll)
choice = models.CharField(max_length=200)
So lets say I want to have something like a drop-down selection field, populated with the question from each Poll in the database. I also want to have a text-field, which displays the corresponding choices for the currently selected Poll, which will update on-the-fly whenever the user selects a different Pool. I've been able to figure this out by placing a button, and posting information back to the form; However, I'm trying to do this automatically as the user makes a selection. My view sort of looks something like this at the moment:
#view.py
from django import forms
from django.shortcuts import render_to_response
from myapp.models import Poll,Choice
class MyModelChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
return "%s" % obj.question
class PollSelectionForm(forms.Form):
polls = MyModelChoiceField( queryset=Poll.objects.all() )
class ChoiceResults(forms.Form):
def __init__(self, newid, *args, **kwargs):
super(ChoiceResults, self).__init__(*args, **kwargs)
self.fields['choice'] = forms.TextField( initial="" )
def main(request):
return render_to_response("myapp/index.html", {
"object": PollSelectionForm(),
"object2": ChoiceResults(),
})
My template is very simple, just something like
{{ object }}
{{ object2 }}
I'm sure the way I'm going about creating the forms is probably not the best either, so feel free to criticize that as well :-) As I mentioned, I've read solutions involving reposting the form, but I want this to happen on-the-fly... if I can repost transparently then that would be fine I guess. I've also seen libraries that will let you dynamically create forms, but that just seems like overkill.
Here is one approach - Django/jQuery Cascading Select Boxes?
You can create a new view that just renders json to a string,
and then trigger an event when you're done selecting from the first list which loads the data dynamically from that json.
I do a similar thing here, populating a form based on a selection in a drop down. Maybe this helps you.
Here is the model of the values used to pre-populate the form:
class OpmerkingenGebrek(models.Model):
opmerking = models.CharField(max_length=255)
advies = models.CharField(max_length=255)
urgentiecodering = models.CharField(max_length=2, choices=URGENTIE_CHOICES_2011)
bepaling = models.CharField(max_length=155,blank=True,null=True)
aard = models.CharField(max_length=3, choices=AARD_CHOICES)
The view that manages the form:
def manage_component(request,project_id,.....):
# get values for pre-populate
og = OpmerkingenGebrek.objects.all()
.........
formset = ComponentForm(request.POST,request.FILES)
.........
)))
return render_to_response(template, {
'formset':formset,
........
'og':og,
},context_instance=RequestContext(request))
The html the renders the form
{% extends "base.html" %}
{% block extra_js %}
<script type="text/javascript" src="/media/js/limitText.js"></script>
<script type="text/javascript" src="/media/js/getValueOpmerking.js"></script>
{% endblock %}
<form enctype="multipart/form-data" method="post" action="">
{{ formset.as_table }}
</form>
<p>Choose default values:</p>
<select id="default" onChange="getValue(this)">
{% for i in og %}
<option value="{{ i.opmerking }} | {{ i.advies }} | {{ i.urgentiecodering }} |
{{ i.aard }} | {{ i.bepaling }}">{{ i.opmerking }}</option>
{% endfor %}
</select>
The javascript that pre-populates the form:
function getValue(sel)
{
//get values
var opm = sel.options[sel.selectedIndex].value;
//split string to parts
var parts = opm.split("|");
// autofill form
var opmerking = document.getElementById("id_opmerking");
opmerking.value = parts[0];
var aanbeveling = document.getElementById("id_aanbeveling");
aanbeveling.value = parts[1];
var opt = document.getElementById("id_urgentie");
var urgentie = opt.selectedIndex;
for(var i=0;i<opt.length;i++){
if(opt.options[i].value == parts[2].split(' ').join('')){
opt.selectedIndex = i;
}};
var opt = document.getElementById("id_aard");
var aard = opt.selectedIndex;
for(var i=0;i<opt.length;i++){
if(opt.options[i].value == parts[3].split(' ').join('')){
opt.selectedIndex = i;
}};
var bepaling = document.getElementById("id_bepaling");
bepaling.value = parts[4];
};

Django Widget Media doesn't work

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.