I've got a model, and my instance called "show_user_image":
class user_image(models.Model):
title = models.CharField(max_length=50)
img = models.imageField(upload_to='/home/blabla')
def show_user_image(self):
return u'<img src="%s" />' % self.img.url
show_user_image.short_description = 'User image'
image_img.allow_tags = True
off course i can use it at my admin list:
list_display = ('title', 'show_user_image')
And my question is: how to use this instance in the edit form?
Something like here:
http://new-media.djangobook.com/content/en/1.0/chapter17/book_extra.png
{% extends "admin/change_form.html" %}
{% block form_top %}
<p>Insert meaningful help message here...</p>
{% endblock %}
but i want:
{% extends "admin/change_form.html" %}
{% block form_top %}
{{ MY-INSTANCE-HERE }}
{% endblock %}
I just need to image display above the form.
Thanks!
John.
The form is admin template is available via adminform.form variable. Your field is named img, so it will be like this (untested):
{% block form_top %}
<img src="{{ adminform.form.img.value }}"/>
{% endblock %}
BTW. Class names in python should use CapitalizedWordsNamingConvention, according to official style guide. You should name the model UserImage instead of user_image.
BTW2: show_user_image is a method, not an instance.
Related
I am trying to get my homepage in Wagtail to show a random image. I followed the Wagtail start guide and tried to incorporate this hack in the template, but I'm getting an error.
home/models.py
from django.db import models
from modelcluster.fields import ParentalKey
from wagtail.core.models import Page, Orderable
from wagtail.core.fields import RichTextField
from wagtail.admin.edit_handlers import FieldPanel,InlinePanel
from wagtail.images.edit_handlers import ImageChooserPanel
class HomePage(Page):
body = RichTextField(blank=True)
content_panels = Page.content_panels + [
FieldPanel('body', classname="full"),
InlinePanel('home_images', label='HomePage Images'),
]
class HomeImages(Orderable):
page = ParentalKey(HomePage, on_delete=models.CASCADE, related_name='home_images')
image = models.ForeignKey(
'wagtailimages.Image', on_delete=models.CASCADE, related_name='+'
)
caption = models.CharField(blank=True, max_length=64)
panels = [
ImageChooserPanel('image'),
FieldPanel('caption'),
]
home/templates/home/home_page.html
{% extends "base.html" %}
{% load static %}
{% load wagtailcore_tags wagtailimages_tags %}
{% block body_class %}template-homepage{% endblock %}
{% block content %}
{{ page.body|richtext }}
{% with page.thiswillfail|random as item %}
<div>
{% image item.image max-1000x1000 %}
<p>{{ item.caption }}</p>
</div>
{% endwith %}
{% endblock content %}
Even after adding some images in the Wagtail admin interface, I get the same error on the homepage: object of type 'DeferringRelatedManager' has no len()
I at least narrowed it down to the "with" statement in home_page.html. The wagtail image object is iterable in a for loop as in the start guide, but it would seem that it doesn't work with the random function. So, how can I get it to pick a random image object to show on the page?
Rather than getting a random image in the template, you could get the random image at the context for the template. This avoids the needs to apply the hack mentioned, and should make the code easier to follow for future.
Each Wagtail Page can provide a few method overrides to customise how the template renders. The simplest for this case would be get_cotext - see https://docs.wagtail.io/en/stable/topics/pages.html#customising-template-context
Django allows for querysets to be randomly ordered with order_by('?'), see https://docs.djangoproject.com/en/3.0/ref/models/querysets/#order-by
Code Example
home/models.py
# models.py
class HomePage(Page):
# ... fields & etc
def get_context(self, request):
context = super().get_context(request)
# Add extra variables and return the updated context
context['random_image'] = self.home_images.order_by('?').first()
return context
home/templates/home/home_page.html
{% extends "base.html" %}
{% load static %}
{% load wagtailcore_tags wagtailimages_tags %}
{% block body_class %}template-homepage{% endblock %}
{% block content %}
{{ page.body|richtext }}
{% image random_image.image max-1000x1000 %}
<p>{{ random_image.caption }}</p>
{% endblock content %}
One of my tables in my app is called Gallery and I have the following class to list all of the objects on that table:
from django.views.generic import ListView
from galleries.models import Gallery
class GalleryList(ListView):
template_name = "path/to/template"
context_object_name = "object_list"
def queryset(self):
return Gallery.objects.order_by('-title')[:20]
And it does the job. On my template I do the following:
{% block gallery_list %}
<h1>Gallery List</h1>
<ul>
{% for gallery in object_list %}
<li><img src="{{ gallery.thumbnail.url }}" />{{ gallery.title }}</li>
{% endfor %}
</ul>
{% endblock %}
Everything works as expected. The thing here is that on my base.html template I have {% block title %} for the meta title tag, {% block description %} for my meta description tag in the header. And I want to be able to declare it somewhere and pass it to the view. To be clear, the variables title and description are strings (ex: title="List of all galleries on website").
On the view I want to do something like:
{% extends "base.html" %}
{% block title %}{{ title }}{% endblock %}
{% block description %}{{ description|default:title }}{% endblock %}
But, on the class GalleryList I don't know where to declare the variables title and description. I don't know if that's possible or proper for Django. I want to do what's right.
Also, as I have a costume template for listing all the galleries I could just do:
{% extends "base.html" %}
{% block title %}List of all galleries on website{% endblock %}
{% block description %}List of all galleries on website...{% endblock %}
But then again, I don't know if that's proper for a well coded Django app. I'm a beginner with Django and I would like to know what's the way to go about this. Hope my question is clear enough.
You can override the ListViews get_context_data method to add whatever additional context variables to you want to the context:
class GalleryList(ListView):
def get_context_data(self, **kwargs):
ctx = super(GalleryList, self).get_context_data(**kwargs)
ctx['title'] = 'My Title'
ctx['description'] = 'My Description'
return ctx
The other approach - of having a template that fills in this information - is also sound. Which is better really depends on how dynamic the data is. If the title/description is based on model data or some other factors, then it makes sense to set it in the view. If it is fixed for a particular template then it is probably cleaner to put in in a template that extends base.html.
Edited my code: In the custom fieldset of a model admin:
{%load app_extras %}
{% if field.field.name == 'mobile' %}
<a target="hiddenIframe" href="http://url_to_call.php?exten={{request.user.employee_profile.extension}}&phone={{ field.field.value }}">Click-to-call</a>
{% my_mobile mobile=field.field.value as mob %}
{% endif %}
{% if field.field.name == 'sms_message' %}{{ mob }}
<a target="hiddenIframe" href="http://url_for_send_sms.php?sms_message={{ field.field.value }}&phone={{ mob }}">Click-to-send-sms</a>
{% endif %}
Here I am trying to access mobile number as well as sms_message fields of the model admin form simultaneously.
I have figured that I need to use custom tags, so I created the templatetags module, with app_extras.py containiging the function to assign the value of mobile and return it as follows:
#register.assignment_tag
def my_mobile(*args, **kwargs):
m_mobile = int(kwargs['mobile'])
return {'m_mobile': m_mobile }
In the template fiedset.html above note changes: This returns a Long value as: {'m_mobile': 1234534519L}
When seen on the browser for url for hyperlink shows:
http://url_for_send_sms.php/?sms_message=fgdfg&phone={%27m_mobile%27:%1234534519L}
How do I access the mobile number? Is my custom tag correct?
I formatted the output in my tag as:
#register.assignment_tag
def my_mobile(*args, **kwargs):
m_mobile = ("%d" %int(kwargs['mobile']))
return {'m_mobile': m_mobile }
In the template fieldset.html changed the code as:
{% if field.field.name == 'sms_message' %}
<a target="hiddenIframe" href="http://url_for_send_sms.php?sms_message={{ field.field.value }}&phone=={{ mob.m_mobile }}">Click-to-send-sms</a>
{% endif %}
Important: Both the mobile number and the sms_message are in the same line of the fieldset in the django modeladmin (in my case). So above code belongs to the loop {% for line in fieldset %} loop
Try
{% for ln in fieldset %}
{% for fld in ln %}
{% if f.field.name == 'mobile' %}
{{ f.field.value }}
{% endif %}
{% endfor %}
{% endfor %}
Maybe this is not the best solution ... but it is solution :)
I want to add some html element (button, "a" tag, etc ) to a django admin page. How can i do it? Please help.
Not sure where you want to add your stuff but this is a solution I found somewhere else on SO to change the HTML of a FileField (in my case i wanted to display the current image in an ImageField).
In other words you can make a widget that modifies the html of the field you want to customize:
# Widget that modifies the output of a FileField
class OutputWidget(AdminFileWidget):
# Overloaded django magic
def render(self, name, value, attrs=None):
output = []
# This is the place where we edit the output
if value and getattr(value, "url", None):
image_url = value.url
output.append(u' <img src="%s" alt="%s" />' % (image_url, image_url, image_url))
output.append(super(AdminFileWidget, self).render(name, value, attrs))
return mark_safe(u''.join(output))
# ModelAdmin class that is applied to the model
class MyModelSettings(admin.ModelAdmin):
# Overloaded django magic
def formfield_for_dbfield(self, db_field, **kwargs):
# Look for the field we want to edit and register the widget with it
if db_field.name == 'nameOfFieldIWantToEdit':
request = kwargs.pop("request", None)
kwargs['widget'] = OutputWidget
return db_field.formfield(**kwargs)
return super(MyModelSettings,self).formfield_for_dbfield(db_field, **kwargs)
# Register my overloaded settings with the model
admin.site.register(MyModel, MyModelSettings)
The code goes into admin.py where you register your models.
From the docs:
The Django admin site
Customizing the Django admin interface
I used Omokoli's solution from above but to make the field use my custom widget I did:
class MyModelAdminForm(forms.ModelForm):
class Meta:
model = get_model('myapp', 'mymodel')
widgets = {
'original_link': OutputWidget,
}
You can create a file under templates/admin called base_site.html
(create the "admin" folder in your app).
add this code:
{% extends "admin/base_site.html" %}
{% load i18n %}
{% block userlinks %}
{% if site_url %}
{% trans 'View site' %} /
{% endif %}
{% if user.is_active and user.is_staff %}
{% url 'django-admindocs-docroot' as docsroot %}
{% if docsroot %}
{% trans 'Documentation' %} /
{% endif %}
{% endif %}
{% if user.has_usable_password %}
{% trans 'Change password' %} /
{% endif %}
{% trans 'Log out' %}
<!-- YOUR CUSTOM CODE HERE -->
<div class="your_custom_class">
{% trans 'your link 1' %} /
{% trans 'your link 2' %}
</div>
{% endblock %}
You can overwrite a lot of the admin html files. Make sure you extends the html you are overwriting, not to loose basic functionality.
See customize-django-admin-python for full admin templates tree you can overwrite.
You can also look at the base_site.html in Django project in Github. You'll find all of the "base_site" blocks you can plant your custom code in.
I'm trying to write a custom inclusion_tag in django.
Following the example on http://docs.djangoproject.com/en/dev/howto/custom-template-tags/
I'm just writing
from django import template
from libmas import models
register = template.Library()
#register.inclusion_tag('records.html')
def display_records(book_id):
book = models.book.objects.get(id__exact=book_id)
records = models.objects.filter(books=book)[0:10]
return {'records':records}
But I'm getting a
Invalid block tag: 'libmas_tags'
error in ie .
'records.html' file:
{% for record in records %}
<blockquote>{{record.id}}</blockquote>
{% endfor %}
my other html file is :
{% extends "admin/change_form.html" %}
{% libmas_tags %}
{% block after_field_sets %}
{% if object_id %}
{% display_records object_id %}
{% endif %}
{% endlock %}
The problem lies in your template. Its calling {% libmas_tags %}. Have you created template tags called libmas_tags? If so you might need to change it to
{% load libmas_tags %}
What is libmas_tags? The tag you have defined is called display_records, and that's what you should be calling in your template. If the tags file is called libmas_tags, you'll need to load that first as czarchaic points out.