Custom Page fields in Mezzanine not displaying in template - django

I am building a CMS in Mezzanine, and all in all I am extremely impressed with the system. I can't tell you how many CMS systems I have attempted to customize in the past and given up in total frustration.
All in all this has been smooth as silk. But I have a custom page for displaying a YouTube video, and the custom field (which is definitely present in the instance, according to the shell) is failing to render in the template.
The app is called mezz_youtube; here is models.py:
from django.db import models
from django.utils.translation import ugettext_lazy as _
from mezzanine.pages.models import Page, RichText
class YouTubePage(Page):
"""
Implements pages with a YouTube video.
"""
video_slug = models.SlugField(u"video ID", max_length=11)
class Meta:
verbose_name = _("YouTube page")
verbose_name_plural = _("YouTube pages")
The Admin works fine and the YouTubePage was created successfully, as the shell shows:
In [1]: from mezz_youtube.models import YouTubePage
In [2]: p = YouTubePage.objects.get()
In [3]: p.pk
Out[3]: 11
In [4]: p.video_slug
Out[4]: u'CKqGbpR4vvM'
But in the template, as shown here with various debugging entries, the custom field does not appear. Here's the template:
{% extends "pages/page.html" %}
{% load mezzanine_tags %}
{% block main %}
<iframe width="853" height="480" src="http://www.youtube.com/embed/{{ page.video_slug }}" frameborder="0" allowfullscreen></iframe>
<p>Video slug is {% if page.video_slug %}present{% else %}absent{% endif %}.</p>
<p>Title: {{ page.title }} </p>
<p>Model: {{ page.content_model }} </p>
<p>fields:</p>
<ul>
{% for field, val in page.fields.iteritems %}
<li>{{ field }}: {{ val }}</li>
{% endfor %}
</ul>
{{ block.super }}
{% endblock %}
Here is the corresponding section of the output:
<iframe width="853" height="480" src="http://www.youtube.com/embed/" frameborder="0" allowfullscreen></iframe>
<p>Video slug is absent.</p>
<p>Title: ladeda </p>
<p>Model: youtubepage </p>
<p>fields:</p>
<ul>
</ul>
As you can see, the title field renders, but the video_slug field does not. Any idea what is going on here?

Related

Django CMS icon in menu

I am trying to show my uploaded icon on navigation but i guess, i am going through a wrong way.
this is my model that extended
class IconExtension(PageExtension):
image = models.ImageField(upload_to='icons')
extension_pool.register(IconExtension)
and this is my cms_toolbars.py file
#toolbar_pool.register
class IconExtensionToolbar(ExtensionToolbar):
# defines the model for the current toolbar
model = IconExtension
def populate(self):
# setup the extension toolbar with permissions and sanity checks
current_page_menu = self._setup_extension_toolbar()
# if it's all ok
if current_page_menu:
# retrieves the instance of the current extension (if any) and the toolbar item URL
page_extension, url = self.get_page_extension_admin()
if url:
# adds a toolbar item in position 0 (at the top of the menu)
current_page_menu.add_modal_item(_('Page Icon'), url=url,
disabled=not self.toolbar.edit_mode_active, position=0)
and this is my menu.html file
{% load menu_tags %}
{% for child in children %}
<li class="child{% if child.selected %} selected{% endif %}{% if child.ancestor %} ancestor{% endif %}{% if child.sibling %} sibling{% endif %}{% if child.descendant %} descendant{% endif %}">
<a href="{{ child.attr.redirect_url|default:child.get_absolute_url }}">{{ child.get_menu_title }}
<img src="{{ child.image.url }}">
</a>
{% if child.children %}
<ul>
{% show_menu from_level to_level extra_inactive extra_active template "" "" child %}
</ul>
{% endif %}
</li>
{% endfor %}
I am not getting why it is not working, I don't see any error even I don't see any image url here, my everything is working fine, only going through problem showing menu icon, can anyone help me in this case?
It looks like you're just missing the reference to the object from the page, you're going straight to it's attribute.
I've got a very similar setup with images associated with pages;
class PageImage(PageExtension):
""" Add images to pages """
image = models.FileField(
verbose_name=_("Image"),
upload_to=upload_to('page_images')
)
Which in my templates becomes;
{% if request.current_page.pageimage.image %}
{{ request.current_page.pageimage.image.url }}
{% endif %}
So in your example, if you did this in a template you'd do;
{% if request.current_page.iconextension %}
<img src="{{ request.current_page.iconextension.image.url }}">
{% endif %}
Checking if the extension exists is important to avoid attribute errors etc.
In a menu, the child isn't a Page object though, it's a NavigationNode from the menu system. So it doesn't have your extension.
I think the proper solution to this is to setup a navigation Modifier. The docs for this are here; http://docs.django-cms.org/en/latest/how_to/menus.html#navigation-modifiers
Alternatively you could setup a template tag which you pass your child which could then use the reverse_id attribute to query the database for the Page that corresponds to, and return the iconextension of that page. I've used this method before.
Based on #markwalker_ answer. I did the job successfully in 3 Steps
Step 1 - Add an FontAwesomeField in a page Extension :
https://docs.django-cms.org/en/latest/how_to/extending_page_title.html
For the record here is my code :
In models.py
from django.db import models
# Create your models here.
from cms.extensions import PageExtension
from cms.extensions.extension_pool import extension_pool
class IconExtension(PageExtension):
image = models.ImageField(upload_to='icons', null=True, blank=True)
fontawesomeicon = models.CharField(max_length=100, null=True, blank=True)
extension_pool.register(IconExtension)
In admin.py
from django.contrib import admin
from cms.extensions import PageExtensionAdmin
from .models import IconExtension
class IconExtensionAdmin(PageExtensionAdmin):
pass
admin.site.register(IconExtension, IconExtensionAdmin)
In cms_toolbars.py
from cms.toolbar_pool import toolbar_pool
from cms.extensions.toolbar import ExtensionToolbar
from django.utils.translation import gettext_lazy as _
from .models import IconExtension
#toolbar_pool.register
class IconExtensionToolbar(ExtensionToolbar):
# defines the model for the current toolbar
model = IconExtension
def populate(self):
# setup the extension toolbar with permissions and sanity checks
current_page_menu = self._setup_extension_toolbar()
# if it's all ok
if current_page_menu:
# retrieves the instance of the current extension (if any) and the toolbar item URL
page_extension, url = self.get_page_extension_admin()
if url:
# adds a toolbar item in position 0 (at the top of the menu)
current_page_menu.add_modal_item(_('Page Icon'), url=url,
disabled=not self.toolbar.edit_mode_active, position=0)
Step 2 - Implementing Navigation Modifier
https://docs.django-cms.org/en/latest/how_to/menus.html#navigation-modifiers
In cms_menu.py
from menus.base import Modifier
from menus.menu_pool import menu_pool
from cms.models import Page
class AddIconModifier(Modifier):
"""
This modifier makes the changed_by attribute of a page
accessible for the menu system.
"""
def modify(self, request, nodes, namespace, root_id, post_cut, breadcrumb):
if breadcrumb:
return nodes
# Only on last iteration (Voir : https://docs.django-cms.org/en/latest/how_to/menus.html#navigation-modifiers)
if not post_cut:
return nodes
# only consider nodes that refer to cms pages
# and put them in a dict for efficient access
page_nodes = {n.id: n for n in nodes if n.attr["is_page"]}
# retrieve the relevent pages
pages = Page.objects.filter(id__in=page_nodes.keys())
# loop over all relevant pages
for page in pages:
# take the node referring to the page
node = page_nodes[page.id]
if hasattr(page, 'iconextension') and hasattr(page.iconextension ,'fontawesomeicon'):
node.attr["faicon"] = page.iconextension.fontawesomeicon
else:
node.attr["faicon"] = 'fa-arrow-circle-right'
return nodes
menu_pool.register_modifier(AddIconModifier)
Step 3 - Specific navigation template
In my main template :
{% show_menu 0 100 100 100 "partials/navigation.html" %}
In my navigation template (navigation.html)
{% load cms_tags menu_tags cache %}
{% for child in children %}
<li class="nav-item">
<a class="nav-link" href="{{ child.attr.redirect_url|default:child.get_absolute_url }}"><i class="fas fa-fw {{ child.attr.faicon }}"></i>{{ child.get_menu_title }}</a>
{% if child.children %}
<ul class="sub_menu">
{% show_menu from_level to_level extra_inactive extra_active template '' '' child %}
</ul>
{% endif %}
</li>
{% endfor %}

Custom input field and custom searchqueryset

I followed the get started doc and everyting work well! :)
But i would like to replace the form in the /search/search.html by a custom form without selectable model checkbox.
In the form i would like to add a button which on click, order search results by a criteria
My questions are:
Which files i need to create or modified to perfoms that and what are their roles?
My codes are:
search_indexes.py
from haystack import indexes
from models import ProduitCommerce
class ProduitIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
commerce = indexes.CharField(model_attr = 'nom_commerce')
nom = indexes.CharField(model_attr = 'nom_produit')
price = indexes.DecimalField(model_attr = 'prix') #Field to filter ON
def get_model(self):
return ProduitCommerce
search/search.html
{% extends 'base.html' %}
{% block content %}
<h2>Search</h2>
<form method="get" action=".">
<table>
{{ form.as_table }} <!------ FORM TO CHANGE BY A CUSTOM FORM BLOCK TO INCLUDE WITH DJANGO ------->
<tr>
<td> </td>
<td>
<input type="submit" value="Search">
</td>
</tr>
</table>
{% if query %}
<h3>Results</h3>
<!---------------------------- PLACE TO INCLUDE THE BUTTON TO FILTER ON result.object.prix------------------>
{% for result in page.object_list %}
<p>
{{ result.object.nom_produit }}{{result.object.prix}}
</p>
{% empty %}
<p>No results found.</p>
{% endfor %}
{% if page.has_previous or page.has_next %}
<div>
{% if page.has_previous %}{% endif %}« Previous{% if page.has_previous %}{% endif %}
|
{% if page.has_next %}{% endif %}Next »{% if page.has_next %}{% endif %}
</div>
{% endif %}
{% else %}
{# Show some example queries to run, maybe query syntax, something else? #}
{% endif %}
</form>
produitcommerce_text.txt
{{ object.nom_produit }}
{{ object.nom_commerce }}
{{ object.description }}
{{ object.prix }}
PS: I'm working on a django project with the 1.5 .1 version and whoosh like haystack backend.
Thanks for you help :)
You are getting the selectable model checkboxes because you're extending the ModelSearchForm:
#forms.py
from haystack.forms import ModelSearchForm
class ProduitForm(ModelSearchForm):
You can easily avoid this behaviour by extending the simple search form variant, provided by the haystack:
#forms.py
from haystack.forms import SearchForm
class ProduitForm(SearchForm):
Then you're going to add something like the following to you application's urls.py:
#urls.py
from haystack.query import SearchQuerySet
from haystack.views import SearchView, search_view_factory
from myapp.models import Produit
urlpatterns = patterns('',
url(r'^produit/search/$', search_view_factory(
view_class=SearchView,
template='search/search.html',
searchqueryset=SearchQuerySet().models(Resume),
form_class=ProduitForm
), name='produit_search'),
)
Please note that there is a bug with .models() filter when trying to use it with latest versions of Haystack and Whoosh. If you would experience any kind of problems with the strategy above, then you should make sure, that your Haystack and Whoosh are of versions 2.0.0 and 2.4.1 relatively - tested and works well.
Also, not related to your question, you might want to avoid using HAYSTACK_SEARCH_RESULTS_PER_PAGE in your settings.py. It also has a very ugly bug. Just sharing my experience. Note that this info is related to Whoosh, everything should work fine with any other backend.

Completely stripping certain HTML Tags in Django forms

I have a ModelForm that posts news items to a database, and it uses a javascript textarea to allow the authorized poster to insert certain pieces of HTML to style text, like bold and italics. However, since I have the template output using the "safe" filter, it outputs all the HTML the form widget tries to pass on. This includes a bothersome <br> tag that never goes away, making it so you can submit without form validation reading the field as empty and stopping you. How can I make that I can not only filter the <br> tag, but completely remove it from the data? Here is relevant code:
Models.py:
from django.db import models
from django.forms import ModelForm, forms
from django.contrib.auth.models import User
# Create your models here.
class NewsItem(models.Model):
user = models.ForeignKey(User)
date = models.DateField(auto_now=True)
news = models.TextField(max_length=100000, blank=False, help_text='HELP TEXT')
def __unicode__(self):
return u'%s %s %s' % (self.user, self.date, self.news)
class NewsForm(ModelForm):
class Meta:
model = NewsItem
exclude=('user','date',)
Views.py:
from news.models import NewsForm, NewsItem
from django.shortcuts import render
from django.http import HttpResponseRedirect, HttpResponse
def news(request):
if request.method == 'POST':
item = NewsItem(user=request.user)
form = NewsForm(request.POST, instance=item)
if form.is_valid():
form.save()
return HttpResponseRedirect('/news/')
else:
form = NewsForm()
news_list = NewsItem.objects.all()
return render(request, 'news_list.html', {'news_list': news_list, 'form': form})
news_list.html:
{% extends "base.html" %}
{% block title %}News in the Corps{% endblock %}
{% block content %}
<h2 id="page_h">News in the Corps</h2>
{% if user.is_authenticated %}
<h3>Post News</h3>
<script src="{{ STATIC_URL }}nicEdit.js" type="text/javascript"></script>
<script type="text/javascript">bkLib.onDomLoaded(nicEditors.allTextAreas);</script>
<div id="news_poster">
<form id="news_poster" action="/news/" method="POST">{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" />
</form>
</div>
{% endif %}
<ul id="events_list">
{% if news_list %}
<div id="news_list">
{% for news in news_list %}
{% if news.id == 1 %}
<hr />
{% endif %}
<div id="{{ news.id }}" class="news_item">
<p class="poster">Posted By: {{ news.user }} | Posted On: {{ news.date }} | Link</p>
<div id="news_item">
{{ news.news|safe }}
</div>
</div>
<hr />
{% endfor %}
</div>
{% endif %}
</ul>
{% endblock %}
You can try the removetags template filter:
{{ news.news|removetags:"br"|safe }}
I can't help but thinking that the "removetags" as Timmy O'Mahony suggested might work if it was structured like this:
{{ news.news|safe|removetags:"br"}}
Give it a shot and see if it works. I would reply, but my karma's not height enough to directly reply to an answer with a suggestion.

Using Django to show YouTube videos in templates

I'm attempting to store a list of YouTube links in a model then passing it as a list to a template where it's rendered using YouTube's embed code. Everything seems to be working fine, the variables are passed properly except the videos don't show up. The YouTube iframe code is just blank whereas a copy/pasted of YouTube embed code displays just fine.
The code in the Model:
from django.db import models
class Video(models.Model):
link = models.URLField()
def __str__(self):
return self.link
The code in the View:
def index(request):
full_list = Video.objects.all()
return render_to_response('index.html', {'full_list': full_list})
The code in the Template:
<h1>YouTube list</h1>
{% if full_list %}
<ul>
{% for video in full_list %}
<li>
<!-- link passed to embed code, this shows up as blank -->
<iframe width="560" height="345" src="{{ video.link }}?rel=0" frameborder="0" allowfullscreen></iframe>
<!-- YouTube embed link copy/pasted as is -->
<iframe width="560" height="345" src="http://www.youtube.com/embed/vLmNvYTTWXM?rel=0" frameborder="0" allowfullscreen></iframe>
</li>
{% endfor %}
</ul>
{% else %}
<p>No videos available</p>
{% endif %}
Screenshot of the browser: https://img.skitch.com/20110910-t78bm288mxh6nmyjmcbxyjr37n.png
I'm guessing that the templates are rendered first and the variable is added second hence YouTube's server is not even called. Is this a correct assumption and if so how do I go about fixing it?
Your code is correct as I can see.
Mb you will show us result html code?
The only thing thay may be wrong is lack of __unicode__ method in your model.
You should use not __str__ but __unicode__.
I wrote a template tag, which does exactly what's needed above.
https://gist.github.com/chhantyal/5396911
You could use this library to make your life easier:
https://github.com/jazzband/django-embed-video
Embed Videos the Easiest Way:
models.py
from django.db import models
from embed_video.fields import EmbedVideoField
class Item(models.Model):
video = EmbedVideoField() # same like models.URLField()
template
{% load embed_video_tags %}
The video tag:
{% video item.video as my_video %}
URL: {{ my_video.url }}
Thumbnail: {{ my_video.thumbnail }}
Backend: {{ my_video.backend }}
{% video my_video "large" %}
{% endvideo %}
Or embed shortcut:
{% video my_video '800x600' %}

django-taggit - how do I display the tags related to each record

I'm using django-taggit on one of my projects and I'm able to save and tie the tags with specific records. Now the question is how do I display the tags related to each record?
For example on my page I want to display a record which contains a title and content and then under it I want to show the tags tied to that record.
What goes in the views.py, and mytemplate.html? Real examples would be truly appreciated.
models.py
from django.db import models
from taggit.managers import TaggableManager
class MyObject(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
tags = TaggableManager()
views.py
from django.views.generic import simple
def show_object(request):
""" View all objects """
return simple.direct_to_template(request,
template="folder/template.html",
extra_context={
'objects':MyObject.objects.all(),
})
template.html
{% for object in objects %}
<h2>{{ object.title }}</h2>
<p>{{ object.content }}</p>
<ul>
{% for tag in object.tags.all %}
<li> {{ tag.name }} </li>
{% endfor %}
</ul>
{% endfor %}
If you are in a hurry you can also try:
{{context_name.tags.all|join:", "}}