How to detect if CloudinaryField in django model is empty in template - django

picture = CloudinaryField('image', blank = True, null = True)
I have the above line in my django models file. And I am rendering the picture in my template with the cloudinary tag
{% cloudinary "filename" %}
But in cases where the model objects don't contain the picture, I want to forgo the template tag. Right now, my template renders a empty image if the model instance doesn't have a picture.
How can I detect if the model instance contains a picture, so that I can render it selectively using the `
{% if condition %}

None, True, False are available in Django templates. So you can do something similar to -
{% if photo.picture == None %}
or
{% if not photo.picture %}
That said, It's not clear as to why allow null values in this field in the first place. This field should contain all relevant details of the image for further manipulation and delivery.

Related

Django admin dashboard, is there a way to lowercase model name?

I'm looking for a way to lowercase the first letter of a model in my django admin site.
i.e.:
model verbose name is "agent-1.0.0" is shown as "Agent-1.0.0" on the dashboard,
simple but IDK
grappelli trick will also work for me.
django - 1.7.1
also - need this only for one app models group - not all of my dashboard should be lowercase...
so, overriding the index.html is not so efficient
The capitalization is hard-coded in the template, same for the templates in Grappelli.
You can use catavaran's suggestion, but this will transform every model name. Overriding the template is a huge pain in the ass to maintain for something this small.
The only workable solution I can think of is to bypass the capfirst filter with a space:
class Meta:
verbose_name = " agent-1.0.0"
As capfirst only forcibly capitalizes the first character, nothing will happen if the first character is not a letter.
Model name passed to template as capfirst(model._meta.verbose_name_plural) so you have to lowercase it in the admin/index.html tempate or via CSS. Imho CSS option is simpler:
div.module tr[class^=model-] th {
text-transform: lowercase;
}
If you want lowercase only some models (for example User) then change CSS selector to this:
div.module tr.model-user th {
text-transform: lowercase;
}
With Grapelli you could create a custom Dashboard by running:
python manage.py customdashboard
and setting GRAPPELLI_INDEX_DASHBOARD on your settings to your custom class.
You can make this custom class extend from the Dashboard class that grappelli offers and override it to your needs. Look especially at the ModelList class, where you can specify the title you want for the model.
There is a CSS-way for those who don't want to override Django admin classes. Override and extend templates/admin/base_site.html template as follows:
{% extends "admin/base_site.html" %}
{% block extrahead %}
<style>
h1.model-title {text-transform: lowercase;}
h1.model-title:first-letter {text-transform: uppercase;}
</style>
{% endblock %}
{% block content_title %}
{% if title %}<h1 class="model-title">{{ title }}</h1>{% endif %}
{% endblock %}
This will make only first letter of each content_title uppercase.
You can use the same way to lowercase model name in admin tables as well as sidebar. However, I'd like to point that by tacit agreement model's verbose_name as well as verbose_name_plural shouldn't be capitalized. This will save you a lot of overrides in your project, like I provided above to normalize change_list header.

Add extra data to choices in Django Admin

I have something like the following:
class Destination(models.Model):
name = models.CharField
picture = models.ImageField
def __unicode__(self):
return u"%s" % self.name
class Vacation(models.Model):
destination = models.ForeignKey(Destination)
When creating the model in my Django Admin interface, I'd like my Destinations to be displayed as radio buttons with the Destination name and Destination picture.
I'm using a custom add_form template so displaying radio buttons with destination name is no problem, but including the picture is difficult.
I would like to leave __unicode__(self) as-is, I only need the picture returned with the object in this admin view. Also I don't want to inline the object.
Any advice on how to do this (including how to incorporate it into the template) would be great!
EDIT: This SO post comes very close to what I need, but I would like to access the individual choice data instead of parsing it from a modified label.
This is not an admin-specific answer, but I think it should work in admin if you can use a custom template for the form.
You could make a modified widget (probably as a subclass of an existing Django widget), that send extra fields from the model to a custom widget template.
You could also render the form manually in the template where it's displayed, and make an inclusion tag that fetches any extra information using the id of your destination object, which is passed as the value of the option.
For example:
your_template.html
{% load destinations %}
{% for opt in form.destination %}
{{ opt.tag }}
{% destination opt.data.value %}
{% endfor %}
destinations.py (in your_app/templatetags)
from django import template
from your_app.models import Destination
register = template.Library()
#register.inclusion_tag('your_app/destination-option.html')
def destination(id):
destination=Destination.objects.filter(id=int(id)).first()
return {'destination':destination}
destination-option.html
<!-- any formatting you prefer -->
{{destination.title}}
<img src="{{destination.picture.image_url}}">

Django : Customizable templates

I am working on creating a web portal and I want to offer the users the feature of making changes to there profile/dashboard like changed background. etc.
Can anybody please guide me to an efficient approach to achieve this?
Thanks
This is trickery that has more to do with css and javascript than with django templates.
The only thing that is django related here is the actual storing of these preferences.
e.g. the filepaths of the actual background images.
After that you will do something similar to what is described in this answer:
how to change html background dynamically
EDIT
I don't see why you need different directories for every user. Django templates
give you more than enough power to do what you want.
For example, let's say that each user can upload his own background picture. Also
I assume that you follow this popular django pattern for storing additional information
about your users. https://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users
So we have this UserProfile model:
class UserProfile(models.Model):
CHOICES = (
('vertical', 'Vertical'),
('horizontal', 'Horizontal'),
)
user = models.OneToOneField(User)
background_image = models.ImageField(upload_to='images')
dashboard_layout = models.CharField(max_length=10, choices=CHOICES)
You can pass this extra information to your javascript context(either with Ajax or without)
and then change the background image for every individual user.
Also we could do special layout at the template level like this:
{% extends "base.html" %}
{% block main_body %}
{% if request.user.get_profile.dashboard_layout == 'vertical' %}
{% include "layouts/vertical.html" %}
{% else %}
{% include "layouts/horizontal.html" %}
{% endif %}
{% endblock main_body %}

django get list of distinct 'children' of ForeignKey related model (and do this in template?)

I'm making a database of released music albums
models.py
class Image(models.Model):
image = models.ImageField(....
class Album(models.Model):
title = models.CharField(....
class Release(models.Model):
album = models.ForeignKey(Album)
cover_art = models.ForeignKey(Image, blank=True, null=True, on_delete=models.SET_NULL)
In my template (at the moment I'm using generic views) I have:
{% for a in album_list %}
{% for r in a.release_set.all %}
{% if r.cover_art %}
# display cover art image
{% endif %}
{% endfor %}
{% endfor %}
The problem is that sometimes an album has been released several times with identical cover art, in which case I'd like to display the image only once, with some text listing the releases it pertains to.
I've tried:
{% for i in a.release_set.cover_art %}
{% for i in a.release_set.cover_art_set %}
{% for i in a.release_set.all.cover_art %}
{% for i in a.release_set.all.cover_art_set %}
Or in a simpler case, I'd at least like to display the images smaller if there are more than one of them.
{% if a.release_set.count > 1 %} # works but displays duplicate images
{% if a.release_set.cover_art_set.count > 1 %} # doesn't work (see above)
Is it possible to get a list of objects related by reversing this ForeignKey lookup then asking for the set of their children? The only way I can think of is by assembling some tuples/lists in the view.
I managed this with a new method on the Album model:
class Album(models.Model):
title = models.CharField(....
def distinct_cover_images(self):
"Returns the queryset of distinct images used for this album cover"
pks = self.release_set.all().values_list('cover_art__pk', flat=True)
distinct_cover_images = Images.objects.filter(pk__in=pks).distinct()
return distinct_cover_images
Then the template is much more simple:
{% for i in a.distinct_cover_images %}
Credit to #danilobargen however for his contribution to this code.
If I understood this right:
An album can have several releases
A release has only one cover
You want to loop over all covers of an album
In that case, the following should work:
{% for release in a.release_set.all %}
{{ release.cover_art.image }}
{% endfor %}
If you want to prevent listing identical covers, you can either compare the covers in the loop, or prepare a set with distinct covers in your view, so you can pass it on to the template.
# Solution using a set
context['distinct_coverimages'] = \
set([r.cover_art.image for r in album.release_set.all()])
# Solution using two queries, might perform better
pks = album.release_set.values_list('cover_art__pk', flat=True)
context['distinct_coverimages'] = models.Image.filter(pk__in=pks).distinct()
A third alternative would be creating a custom template filter for your album, to return all distinct release covers.
In any case, I recommend debugging such things in your Django shell. You can issue the shell with ./manage.py shell. If you have installed django-extensions, you can also use ./manage.py shell_plus to autoload all models. All object attributes and functions that don't require arguments (e.g. normal instance attributes or instance functions without arguments like 'string'.isalnum()) can also be used the same way (just without the parentheses) in your template.

How to give a column in the Django admin change_list a CSS class

I'd like to change the column widths in the list display of the Django admin.
Is it possible somehow to add a CSS classname to a column?
I'd preferably not overwrite the entire template to accomplish this.
In Django >= 1.6, CSS classes are included with list_display output:
"The field names in list_display will also appear as CSS classes in the HTML output, in the form of column-<field_name> on each <th> element. This can be used to set column widths in a CSS file."
While this feature is implemented in vers1.6 as StvnW said, for earlier versions you can do the following:
In admin.py:
class MyModelAdmin(admin.ModelAdmin):
# your code here
# specify a stylesheet just for the list view
class Media:
css = {'all': ('css/mymodel_list.css')}
In mymodel_list.css:
/* replace '5' with the column desired */
table#result_list td:nth-child(5) {
width: 15em;
}
Specifying table#result_list will apply this stylesheet only to the list view and won't affect the normal admin page for this model. Also, note that while django uses th for the first column of the model, it still counts for a td child.
There is an open ticket that addresses the need for specifying css classes for table columns in the change_list view.
That said ... in the description for the ticket there's a snippet that injects a custom stylesheet in your change_list-template:
{% extends "admin/change_list.html" %}
{% block extrastyle %}
{{ block.super }}
<link rel="stylesheet" type="text/css" href="/css/poll_admin_changelist.css" />
{% endblock extrastyle %}
So you don't override the whole template, only the part (extrastyle) you need.
Now you could inject your own stylesheet and for example style your columns using the :nth-child-selector
Another option would be to wrap your specific fields in html which can be done using the list_display option. Here you could define a width or class for a wrapped element.
This does only makes sense though, if you want to control the width of limited set of fields