Can not display my comment lists for a post - django-templates

i have tried to add and display comments list in my django post_detail template yet its not displaying...
This is my comment models...
class Comment(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, default=1, on_delete=models.CASCADE)
content = models.TextField()
active = models.BooleanField(default=True)
created = models.DateTimeField(blank=True, auto_now=False, auto_now_add=True)
class Meta:
ordering = ['created']
def __str__(self):
return "Comment by {} on {}".format(self.author, self.content)
i then added the comment model into my post module as follows...
from comments.models import Comment
class Post(models.Model):
comment = models.ForeignKey(Comment, blank=True, null=True)
Here is my post views.py
def post_detail(request, slug):
post = get_object_or_404(Post, slug=slug)
return render(request, "blog/post_detail.html", {
'post':post,
})
comments = post.comment.filter(active=True)
if request.method == 'POST':
#A comment was posted
comment_form = CommentForm(request.POST or None)
if comment_form.is_valid() and user.is_authenticated():
#Create new comment but dont save to DataBase first
new_comment = comment_form.save(commit = False)
#Assigns the current instance to the comment
new_comment.post = post
#Saves the comment to DataBase
new_comment.save()
else:
comment_form = CommentForm()
return render(request, "blog/post_detail.html", {
'post':post,
'comments': comments,
'comment_form': comment_form
})
finally i tried to display these into my template yet i couldn't get the list of comments for each post
<!-- displays available comments for this post -->
{% for comment in comments %}
<div class="media d-block d-md-flex">
<img class="d-flex rounded-circle avatar z-depth-1-half mb-3 mx-auto" src="https://mdbootstrap.com/img/Others/documentation/img (2)-mini.jpg" alt="Avatar">
<div class="media-body text-center text-md-left ml-md-3 ml-0">
<h5 class="mt-0 font-weight-bold blue-text">comment {{ forloop.counter }} by {{ comment.author }} {{ comment.created }}</h5>
{{ comment.content|linebreaks }}
</div>
</div>
{% endfor %}
</div>
</div>
<!--/.Comments-->
{% endif %}
<!-- Displays comment form for registered users else link visitors to registeration page -->
{% if user.is_authenticated %}
{% if new_comment %}
<h4><span class="badge badge-pill green">your comment has been added<i class="fa fa-check" aria-hidden="true"></i></span></h4>
{% else %}
<form method="POST">
{% csrf_token %}
<div class="form-group shadow-textarea">
<label for="exampleFormControlTextarea6">Add a comment</label>
<textarea class="form-control z-depth-1" id="exampleFormControlTextarea6" rows="3" placeholder="Write something here...">
{{ comment_form.as_p }}
</textarea>
</div>
<div class="text-center mt-4">
<button class="btn btn-info btn-md" type="submit" value="add comment">submit</button>
</div>
</form>
{% endif %}
{% else %}
<h4>You have to register in order to comment this post </h4>
{% endif %}
please i need help getting this to display
it have eaten up my day.

I finally found the error...
i was rendering the post_detail template before the comment_form
here is my final code
def post_detail(request, slug):
post = get_object_or_404(Post, slug=slug)
comments = Comment.object.filter(active=True)
if request.method == 'POST':
#A comment was posted
comment_form = CommentForm(request.POST or None)
if comment_form.is_valid() and user.is_authenticated():
#Create new comment but dont save to DataBase first
new_comment = comment_form.save(commit = False)
#Assigns the current instance to the comment
new_comment.post = post
#Saves the comment to DataBase
new_comment.save()
else:
comment_form = CommentForm()
return render(request, "blog/post_detail.html", {
'post':post,
'comments': comments,
'comment_form': comment_form
})

Related

'size' on custom product metafield returns '0'

I'm building a component which checks the character count of a custom product metafield; if it's above 24 characters, the data is output as an accordion, otherwise the metafield content is printed in its entirety. The conditional below fails as the metafield size always returns 0, but I can see the content printing via the else statement so I'm certain the path is valid:
{% if product.metafields.custom.product_note.size >= 24 %}
<div class="product-note has--dropdown">
<span class="item__heading item__trigger">Product information</span>
<div class="item__content">
{{ product.metafields.custom.product_note }}
</div>
</div>
{% else %}
<div class="product-note">
<div class="item__content">
{{ product.metafields.custom.product_note }}
</div>
</div>
{% endif %}
I'm not sure it's relevant, but the product_note metafield is a multi-line text field. If anyone could point me in the right direction as to why size is failing to produce a value, I'd appreciate it massively.
You could always try working off the value contained in the metafield. It appears you are short-cutting by referring to just the combo of namespace and key, without actually saying: what is the length of the value stored at that namespace and key. Just a thought. You could at least try that.
Final answer, courtesy of #David Lazar's suggestion:
{% assign data_product_note = product.metafields.custom.product_note.value %}
{% if data_product_note.size >= 24 %}
<div class="product-note has--dropdown">
<span class="item__heading item__trigger">Product information</span>
<div class="item__content">
{{ data_product_note }}
</div>
</div>
{% else %}
<div class="product-note">
<div class="item__content">
{{ data_product_note }}
</div>
</div>
{% endif %}

Render image in left and right side of the screen alternatively

I want to render image in left and right side of the screen alternatively, dynamically in django template. I am not sure how to render it, like if it is 0th for loop counter the image should appear on the left of the screen, for the next iteration the image should render in right and so on.
This is my requirement
This is what I have achieved
Code below
HTML
{% block content %}
<!-- Banner -->
<div class="banner">
<div class="container-fluid banner-content">
<h3>{{page.banner_head}}</h3>
{{page.banner_desc|richtext}}
</div>
</div>
<section class="solution-section">
<div class="container-fluid">
{% for i in page.solutions.all %}
<div class="row pb-5">
<!-- Image -->
<div class="col-md-6">
<div class="solution-image">
<figure class="text-center">
<h6>{{ i.img_text }}</h6>
</figure>
{% image i.sol_img original as img %}
<img src="{{ img.url }}" class="img-fluid solution-index-image" alt="{{ img.alt }}">
</div>
</div>
<!-- Text -->
<div class="col-md-6 solution-desc">
<h5>{{i.sol_head}}</h5>
{{i.sol_desc|richtext}}
learn more
</div>
</div>
{% endfor %}
</div>
</section>
{% endblock %}
models.py
class SolutionPage(Page):
banner_head = models.CharField('Banner Title', blank=True, max_length=255)
banner_desc = RichTextField('Banner Description', blank=True)
content_panels = Page.content_panels + [
MultiFieldPanel([
FieldPanel('banner_head'),
FieldPanel('banner_desc'),
], heading='Banner Section'),
InlinePanel('solutions', label='Solution Details'),
]
class Solution(Orderable):
sol_img = models.ForeignKey(
'wagtailimages.Image',
null = True,
blank = True,
on_delete = models.SET_NULL,
related_name = '+',
verbose_name = 'Solution Image',
)
img_text = models.CharField('Image Text', blank=True, max_length=255)
sol_head = models.CharField('Solution Heading', max_length=100, blank=True)
sol_desc = RichTextField('Solution Description', blank=True)
sol_link = models.CharField('Button Link', max_length=255, blank=True)
page = ParentalKey('SolutionPage', related_name='solutions')
panels = [
ImageChooserPanel('sol_img'),
FieldPanel('img_text'),
FieldPanel('sol_head'),
FieldPanel('sol_desc'),
FieldPanel('sol_link')
]
Check odd/even in the template with {% if forloop.counter|divisibleby:"2" %}.

Shopify Palo Alto Theme; Attempting to include an 'Add To Cart' in product-grid-item

I know that Timber/Palo Alto is no longer supported but I am working on an old account that uses it and am not familiar with the theme.
I have been able to create a button that adds an item to a cart but after clicking add to cart it redirects to the cart page, I just want to add the item and allow the user to still browse the collection.
Any suggestions will be helpful, Thank you in advance
<!-- /snippets/product-grid-item.liquid -->
<form action="/cart/add" data-productid="{{product.id}}" method="post" enctype="multipart/form-data" id="AddToCartForm--{{section.id}}">
<div class = "variants-wrapper">
{% if variants_count > 1 %}
<select name="id" data-productid="{{product.id}}" id="productSelect--{{section.id}}" class="product-single__variants">
{% for variant in product.variants %}
{% if variant.available %}
<option {% if variant == product.selected_or_first_available_variant %} selected="selected" {% endif %} data-sku="{{ variant.sku }}" value="{{ variant.id }}">{{ variant.title }} - {{ variant.price | money_with_currency }}</option>
{% else %}
<option disabled="disabled">
{{ variant.title }} - {{ 'products.product.sold_out' | t }}
</option>
{% endif %}
{% endfor %}
</select>
{% else %}
<input name="id" data-productid="{{product.id}}" type="hidden" value="{{ product.variants[0].id }}">
{% endif %}
{% if sold_out %}
<input type="hidden" type="text" id="Quantity1" name="quantity" value="0" min="0" class="quantity-selector quantity-input">
<a class="btn" href="{{ product.url | within: collection }}">{{ 'products.product.view_item' | t }}</a>
{% else %}
<div class="qtydiv">
<input type="text" id="Quantity1" name="quantity" value="1" min="1" class="quantity-selector quantity-input">
</div>
<button type="submit" name="add" id="AddToCart" class="btn" style="display: inline">
<span id="AddToCartText">{{ 'products.product.add_to_cart' | t }}</span>
</button>
{% endif %}
</div>
</form>
ajax-cart.js.liquid
ShopifyAPI.addItemFromForm = function(form, callback, errorCallback) {
var params = {
type: 'POST',
url: '/cart/add.js',
data: jQuery(form).serialize(),
dataType: 'json',
success: function(line_item) {
if ((typeof callback) === 'function') {
callback(line_item, form);
}
else {
ShopifyAPI.onItemAdded(line_item, form);
}
},
error: function(XMLHttpRequest, textStatus) {
if ((typeof errorCallback) === 'function') {
errorCallback(XMLHttpRequest, textStatus);
}
else {
ShopifyAPI.onError(XMLHttpRequest, textStatus);
}
}
};
jQuery.ajax(params);
};
This redirects to cart page, because that is how form action value is defined. So if you want to add it without page redirect and reload, use Shopify AJAX API that allows you manage CRUD operations on cart. Shopify AJAX API.
In the above scenario, you need to have a look at Add to Cart functionality.
Post Data
{
quantity: 2,
id: 794864229
}
Sample Code
// Send a seralized form
jQuery.post('/cart/add.js', $('form[action="/cart/add"]').serialize());
// or construct post data
jQuery.post('/cart/add.js', {
quantity: 1,
id: 794864229,
properties: {
'First name': 'Caroline'
}
});
Another approach that is a bit easy to implement is to use CartJS
So using data API, it would just be
<button data-cart-add="12345678">Add Product</button>
Sample implementation on Timber Shopify theme
in theme.liquid after timber.js load CartJS
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/shopify-cartjs/0.4.1/cart.min.js"></script>
Then below that in the jQuery ready function, initialize CartJS
CartJS.init({{ cart | json }}, {
"dataAPI": true
});
The add this code in product-grid-item.liquid
<button data-cart-add="{{ product.variants.first.id }}">Add Product</button>
This is working on my test installation of Timber theme.

Wrap Phalcon flash messages in HTML element

Is there a possibility to wrap flash messages in an element? I want to have no html element at all when there are no messages and have an extra div containing all messages if there is any message.
It would be enough if I could at least get information whether there are any flash messages and then code it myself, but it seems to me that neither Phalcon\Flash\Direct nor Phalcon\Flash\Session allow you to access current message count or wrap messages in your own html element.
Just configure your flash service to just output the message:
$this->flash->setAutomaticHtml(false);
Also, when outputting a message, it's automatically echoed.
If you want to just return a string without echoing it to the output buffer use:
$this->flash->setImplicitFlush(false);
These methods aren't in the main documentation page, but you should always look at the class reference too, you might find very usefull information there :)
EDIT
To return only messages you use setAutomaticHtml to false, setImplicitFlush has nothing to do with it. Also to know if a message exists use something like this:
$this->flashSession->has('error');
I have ended with following code. I basically had to generate output myself.
<?php
$messages = $this->flashSession->getMessages();
if ( count($messages) > 0) {
?>
<div class="basic-bg">
<div class="main-column">
<div class="flash-messages">
<?php
foreach ($messages as $messageType => $messageArray) {
foreach ($messageArray as $message) {
echo "<div class=\"flash-$messageType\">$message</div>";
}
}
?>
</div>
</div>
</div>
<?php } ?>
I know this is an old thread, but how about implementing an extended class to make sure your message string is still correctly escaped?
This is the class I've used to implement Bootstrap 3 dismissable messages:
<?php
namespace Ext;
/**
* Extension to Phalcon Framework to implement Bootstrap 3 dismissable messages.
* Pass mappings of phalcon to bootstrap classes to construct
* #link https://docs.phalconphp.com/uk/latest/reference/flash.html Phalcon flash docs
* #author Kevin Andrews <kevin#zvps.uk>
*/
class FlashBootstrap extends \Phalcon\Flash\Session
{
/**
* Correctly escapes the message while building a Bootstrap 3
* compatible dismissable message with surrounding html.
* #param string $type
* #param string $message
* #return void
*/
public function message($type, $message)
{
$bootstrapCssClass = $this->_cssClasses[$type];
$errorType = ucfirst($type);
$bootstrapMessage = "<div class=\"alert alert-{$bootstrapCssClass} alert-dismissible\" role=\"alert\"><button type=\"button\" class=\"close\" data-dismiss=\"alert\" aria-label=\"Close\"><span aria-hidden=\"true\">×</span></button><strong>{$errorType}:</strong> {$this->getEscaperService()->escapeHtml($message)}</div>";
parent::message($type, $bootstrapMessage);
}
}
Also for completeness the initialisation for DI:
<?php
$di->set('flash', function() {
$bootstrapFlash = new Ext\FlashBootstrap(array(
'error' => 'alert alert-danger alert-dismissible',
'success' => 'alert alert-success alert-dismissible',
'notice' => 'alert alert-info alert-dismissible',
'warning' => 'alert alert-dismissible',
));
$bootstrapFlash->setAutoescape(false);
$bootstrapFlash->setAutomaticHtml(false);
return $bootstrapFlash;
});
This also has the advantage that the ->success() ->error() ->notice() and ->warning() helper methods will all go through this code and produce nicely formatted messages wrapped in the desired HTML.
{% if flash.has('notice')==true OR flash.has('success') %}
{% for notif in flash.getMessages('success') %}
<div class="notif_global success">
<div class="notif_global-title">Успешно</div>
<div class="notif_global-content">{{ notif }}</div>
<div class="notif_global-close ico_close"></div>
</div>
{% endfor %}
{% for notif in flash.getMessages('notice') %}
<div class="notif_global success">
<div class="notif_global-title">Сообщение</div>
<div class="notif_global-content">{{ notif }}</div>
<div class="notif_global-close ico_close"></div>
</div>
{% endfor %}
{% endif %}
{% if flash.has('warning')==true OR flash.has('error') %}
{% for notif in flash.getMessages('warning') %}
<div class="notif_global error">
<div class="notif_global-title">Предупреждение</div>
<div class="notif_global-content">{{ notif }}</div>
<div class="notif_global-close ico_close"></div>
</div>
{% endfor %}
{% for notif in flash.getMessages('error') %}
<div class="notif_global error">
<div class="notif_global-title">Ошибка</div>
<div class="notif_global-content">{{ notif }}</div>
<div class="notif_global-close ico_close"></div>
</div>
{% endfor %}
{% endif %}

How do i dynamically/evaluate via expression json property in django template

reading in a JSON for sport. using a partial for matchup markup.
awayteam and home team for most part share identical markup but the JSON properties which I have no control are such below:
<div class="away {{game.awayTeam_last_name|slugify}}">
<a href="#" title="{{game.awayTeam_first_name}} {{game.awayTeam_last_name}}">
<span class="{{league}}-logo"></span>
<span class="city">{{game.awayTeam_first_name}}</span>
{% if game.event_status != "pre-event" %}
<span title="score">{{game.awayTeam_score}}</span>
{% else %}
<span title="record entering game">(0-0)</span>
{% endif %}
</a>
</div>
<span>#</span>
<div class="home {{game.homeTeam_last_name|slugify}}">
<a href="#" title="{{game.homeTeam_first_name}} {{game.homeTeam_last_name}}">
<span class="{{league}}-logo"></span>
<span class="city">{{game.homeTeam_first_name}}</span>
{% if game.event_status != "pre-event" %}
<span title="score">{{game.homeTeam_score}}</span>
{% else %}
<span title="record entering game">(0-0)</span>
{% endif %}
</a>
</div>
is there a way to shrink/refactor the above like some expression valuator to make home and away passed via a variable.
didn't answer own question but i did get Data guys to better format the data, so became..
awayteam: { first_name:'', last_name:'', score:'' }
hometeam: { first_name:'', last_name:'', score:'' }
allowing me to shrink in half the template =)