How can I show rating in product comments - django

My models:
class Comment(models.Model):
product = models.ForeignKey(Product ,on_delete=models.CASCADE, related_name='comments')
user = models.ForeignKey(User ,on_delete=models.CASCADE, max_length=80, related_name='comments_user')
body = models.TextField()
created_on = jmodels.jDateField(auto_now_add=True)
created_on_time = models.TimeField(auto_now_add=True,null=True)
active = models.BooleanField(default=False)
class Meta:
ordering = ['created_on']
def __str__(self):
return 'Comment {} by {}'.format(self.body, self.user)
class Rating(models.Model):
product = models.ForeignKey(Product ,on_delete=models.CASCADE)
user = models.ForeignKey(User ,on_delete=models.CASCADE)
score = models.IntegerField(default=0,
validators=[
MaxValueValidator(5),
MinValueValidator(0),
]
)
def __str__(self):
return 'rate {} by {} for {}'.format(self.score, self.user, self.product)
In product single page, I have comments part that I want show user rating if that user put comment in next of username and comment date.
My views :
def product_details(request, category_url, subcategory_url, product_url):
product = get_object_or_404(Product, product_url=product_url)
stocks = Stock.objects.filter(product=product)
rate = Rating.objects.filter(product=product, user=request.user)
all_rates = Rating.objects.filter(product=product)
all_rate_count = Rating.objects.filter(product=product).count()
all_rate = sum([all_rate.score for all_rate in all_rates])
all_rate = all_rate/all_rate_count
all_rate = all_rate*100/5
comments = product.comments.filter(product=product, active=True)
if request.method == "POST":
body = request.POST['body']
new_comment = Comment(user=request.user,product=product, body=body)
new_comment.save()
message_good = "نظر شما با موفقیت ثبت شد بعد از برسی نمایش داده میشود!"
ctx = {'product':product, 'stocks':stocks, 'rate':rate, 'all_rate':all_rate,
'comments':comments,
'message_good':message_good,
'all_rate_count':all_rate_count}
return render(request, 'products/product_details.html', ctx)
ctx = {'product':product, 'stocks':stocks, 'rate':rate, 'all_rate':all_rate,
'comments':comments,
'all_rate_count':all_rate_count}
return render(request, 'products/product_details.html', ctx)
And my html :
{% for comment in comments %}
<div class="comments" style="padding: 10px;">
<p class="font-weight-bold">
{{ comment.user }}
<span class=" text-muted font-weight-normal">
{{ comment.created_on }}
</span>
<span class=" text-muted font-weight-normal">
{{ comment.created_on_time|date:"G:i" }}
</span>
</p>
{{ comment.body | linebreaks }}
</div>
{% endfor %}
I updated my codes, and showed my views and my single html
so if please can help me about showing product rate by user for each comment that filtered by user.
or any better suggestion for other ways about rating or showing comments for single product page. thanks for helping

I would add a unique_together constraint to enforce that a user can only leave a single rating for a product.
class Rating(models.Model):
product = models.ForeignKey(Product ,on_delete=models.CASCADE)
user = models.ForeignKey(User ,on_delete=models.CASCADE)
score = models.IntegerField(default=0,
validators=[
MaxValueValidator(5),
MinValueValidator(0),
]
)
class Meta:
unique_together = ('product', 'user')
def __str__(self):
return 'rate {} by {} for {}'.format(self.score, self.user, self.product)
In your views, since you will only have one rating for a product per user.
rate = Rating.objects.get(product=product, user=request.user)
In your templates:
{% for comment in comments %}
<div class="comments" style="padding: 10px;">
<p class="font-weight-bold">
{{ comment.user }}
<span class=" text-muted font-weight-normal">
{{ comment.created_on }}
</span>
<span class=" text-muted font-weight-normal">
{{ comment.created_on_time|date:"G:i" }}
</span>
</p>
{{ comment.body | linebreaks }}
{{ rate.score }}
</div>
{% endfor %}

Related

Django form scrubs blank spaces

I have a model with a text field:
models.py
class Techtip(models.Model):
title = models.CharField(max_length=150)
year = models.PositiveIntegerField()
year2 = models.PositiveIntegerField()
make = models.CharField(max_length=30)
model = models.CharField(max_length=30)
description = models.TextField(max_length=10000)
user = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
date_created = models.DateTimeField(auto_now_add=True)
date_revised = models.DateTimeField(null=True)
additional_field = models.TextField(max_length=5000, null=True, blank=True)
additional_field2 = models.TextField(max_length=5000, null=True, blank=True)
image1 = models.ImageField(upload_to=user_directory_path, null=True, blank=True)
image2 = models.ImageField(upload_to=user_directory_path, null=True, blank=True)
image3 = models.ImageField(upload_to=user_directory_path, null=True, blank=True)
def __str__(self):
return self.title
If a create a Techtip and give it a description of:
"Hello, This is line one of the disctription.
This is line two.
and this is line 3."
When using {{techtip.deescription}} in the template I receive this:
"Hello, This is line one of the disctription.
This is line two.
and this is line 3."
However, if you bring up a form to edit the description, the spaces are there. It is also displayed correctly in the admin panel.
Here is the form:
forms.py
class TechtipFormModel(forms.ModelForm):
"""This form creates and edits techtips."""
class Meta:
model = Techtip
fields = '__all__'
exclude = ('user', 'date_revised', 'additional_field', 'additional_field2', 'image1', 'image2', 'image3')
def __init__(self, *args, **kwargs):
super(TechtipFormModel, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_id = 'id-TechtipForm'
self.helper.form_method = 'post'
self.helper.add_input(Submit('submit', 'Submit'))
self.fields['description'].strip = False
Here are the views for editing a Techtip or displaying one. The spacing works correctly when using the edit form but not while displaying a Techtip.
views.py
#login_required
def techtip_detail(request, pk):
# display techtip details. In template: if user is the creator of Techtip they can update/delete
tech_id = pk
user = request.user
techtip = Techtip.objects.get(pk=tech_id)
context = {'techtip': techtip}
return render(request, 'techtips/view_techtip.html', context)
class TechtipEdit(LoginRequiredMixin,
UpdateView,):
model = Techtip
form_class = TechtipFormModel
template_name = 'techtips/edit_techtip.html'
def get_success_url(self):
return reverse('manage_techtips')
def dispatch(self, request, *args, **kwargs):
# check for user logged in
# check for user permission:
# Take pk from kwargs
pk = kwargs.get('pk') # example
# Take user from request
user = request.user
# check permission
try:
Techtip.objects.get(pk=pk, user=user)
return super(TechtipEdit, self).dispatch(request, *args, **kwargs)
except Techtip.DoesNotExist:
return HttpResponse(status=403)
and here are the templates!
view_techtip.html
{% extends "techtips/base.html" %}
{% block body %}
<div class="row">
<div class="col-md-12">
<div class="container-fluid" align="left">
<div id="punchlist">
<h3 style="margin-bottom: 0px;">Title:</h3>{{ techtip.title }}<br>
<h3 style="margin-bottom: 0px; margin-top: 20px;">Make:</h3> {{ techtip.make }}<br>
<h3 style="margin-bottom: 0px; margin-top: 20px;">Model:</h3> {{ techtip.model }}<br>
<h3 style="margin-bottom: 0px; margin-top: 20px;">Beginning Year:</h3> {{ techtip.year }}<br>
<h3 style="margin-bottom: 0px; margin-top: 20px;">Ending Year:</h3> {{ techtip.year2 }}<br>
<h3 style="margin-bottom: 0px; margin-top: 20px;">Description:</h3> {{ techtip.description }}<br>
</div>
</div>
</div>
</div>
{% if techtip.user.id == user.pk or request.user.is_superuser == TRUE %}
<br>
<form method="GET" action="{% url 'edit_techtip' techtip.pk %}">
<span class="techtip-button-1">
<button type="submit" value="EDIT">Edit</button>
</span>
</form>
{% endif %}
{% if request.user.is_superuser == TRUE %}
<form method="POST" action="{% url 'delete_techtip' techtip.pk %}">
{% csrf_token %}
<span class="techtip-button-1">
<button type="submit" value="DELETE">Delete</button>
</span>
</form>
{% endif %}
<br><br>
<br>
{% if techtip.user.id != user.pk %}
Author: {{techtip.user}}
{% endif %}
{% if techtip.user.id == user.pk %}
Author: You
{% endif %}
{% endblock %}
and
edit_techtip.html
{% extends 'techtips/base.html' %}
{% block body %}
{% load crispy_forms_tags %}
{% crispy form form.helper %}
{% endblock %}
Thanks in advance!
I did some research and added
self.fields['description'].strip = False
to the form class but then later realized that wouldn't help because this form class has no part of passing an object into the template and using Django template language.

try to update a my Cart with django, but i don't know whats im implementing wrong here

Django version = 4.0.4
Python == 3.9.12
os = osx
here is my cart template, where I use a template tag to get access to my Order instance data for render it
<div class="block-cart action">
<a class="icon-link" href="{% url 'core:cart' %}">
<i class="flaticon-shopping-bag"></i>
<span class="count">{{ request.user|cart_item_count }}</span>
<span class="text">
<span class="sub">Carrito:</span>
Gs.{{ request.user|cart_total_count }} </span>
</a>
<div class="cart">
<div class="cart__mini">
<ul>
<li>
<div class="cart__title">
<h4>Carrito</h4>
<span>( {{ request.user|cart_item_count }} Item en el carrito)</span>
</div>
</li>
{% if request.user|cart_total_items != 0 %}
{% for order_item in request.user|cart_total_items %}
<li>
<div class="cart__item d-flex justify-content-between align-items-center">
<div class="cart__inner d-flex">
<div class="cart__thumb">
<a href="product-details.html">
<img src="{{ order_item.item.image.url }}" alt="">
</a>
</div>
<div class="cart__details">
<h6>{{ order_item.item.title }}</h6>
<div class="cart__price">
<span>Gs. {% if order_item.item.discount_price|stringformat:".0f" %} {{ order_item.item.discount_price|stringformat:".0f" }}
{% else %} {{ order_item.item.price|stringformat:".0f" }}
{% endif %} x {{order_item.quantity}}</span>
</div>
</div>
</div>
<div class="cart__del">
<i class="fal fa-times"></i>
</div>
</div>
</li>
{% endfor %}
{%else%}
{% endif %}
<li>
<div class="cart__sub d-flex justify-content-between align-items-center">
<h6>Subtotal</h6>
<span class="cart__sub-total">Gs.{{ request.user|cart_total_count }}</span>
</div>
</li>
<li>
Ver Carrito
Finalizar Compra
</li>
</ul
</div>
</div>
here is the custom template tag
#register.filter
def cart_item_count(user):
if user.is_authenticated:
qs = Order.objects.filter(user=user, order_completed=False)
qs = qs.last()
if qs.order_completed == False:
print(qs.order_completed)
return qs.items.count()
else:
return 0
return 0
here my model
class Order(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
company_name = models.CharField(max_length=100, null=True, blank=True)
items = models.ManyToManyField(OrderItem)
start_date = models.DateTimeField(auto_now_add=True)
direction = models.CharField(max_length=100, blank=True, null=True)
city = models.CharField(max_length=200, null=True, blank=True)
phone = models.CharField(max_length=200, null=True, blank=True)
received = models.BooleanField(default=False)
order_completed = models.BooleanField(default=False)
class Meta:
verbose_name = "Pedido"
verbose_name_plural = "Pedidos"
ordering = ['-id']
def __str__(self):
return self.user.username
def get_total(self):
total = 0
for order_item in self.items.all():
total += order_item.get_total_item_price()
return total
here my checkout view
class CheckoutView(View):
def get(self, *args, **kwargs):
try:
order = Order.objects.get(user=self.request.user, order_completed=False)
form = CheckoutForm()
context = {
'form': form,
'order': order,
}
order.save()
return render(self.request, "v2/checkout.html", context)
except ObjectDoesNotExist:
messages.info(self.request, "Usted no tiene un pedido activo")
return redirect("core:checkout")
def post(self, *args, **kwargs):
form = CheckoutForm(self.request.POST or None)
try:
order = Order.objects.get(user=self.request.user, order_completed=False)
if form.is_valid():
order = form.save(commit=False)
order.order_completed = True
order.user = self.request.user
order.save()
return HttpResponseRedirect('success')
except ObjectDoesNotExist:
messages.warning(self.request, "Usted no posee ningún pedido aun")
return redirect("core:cart")
return HttpResponseRedirect('v2/checkout')
what im tryng is when y make the post form from checkout i save my order change it property order_completed to True, redirect to a succes page, but even if a reload the page, the value of my cart still with the last Order, even if try to filter it by it property
here is my admin interface from my order model before i send the POST
Here is after the POST
here when i go to my redirect succes page it suppose that i have to see my cart empty because the filter template tag but, my order still with the old information
even if i reload cleaning cache still wrong, what im doing wrong?, whats is the correct way to do this?

Django UNIQUE constraint failed: players_comment.user_id

I'm trying to post comment but it's not getting posted, rather this error is appearing UNIQUE constraint failed: players_comment.user_id. I don't know why this error is occuring.
My forms.py:
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('body', 'transfernews')
My models.py :
class Transfernews(models.Model):
player_name = models.CharField(max_length=255)
player_image = models.CharField(max_length=2083)
player_description = models.CharField(max_length=3000)
date_posted = models.DateTimeField(default=timezone.now)
class Comment(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
transfernews = models.ForeignKey(Transfernews, related_name="comments", on_delete=models.CASCADE)
body = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '%s - %s' % (self.transfernews.player_name, self.user.username)
My views.py:
def transfer_targets(request):
transfernews = Transfernews.objects.all()
form = CommentForm(request.POST or None)
if form.is_valid():
new_comment = form.save(commit=False)
new_comment.user = request.user
new_comment.save()
return redirect('transfernews/')
return render(request, 'transfernews.html', {'transfernews': transfernews, 'form': form})
My transfernews.html:
{% for transfer in transfernews %}
{% if not transfer.comments.all %}
No comments Yet...
{% else %}
{% for comment in transfer.comments.all %}
<strong>
{{ comment.user.username }} - {{ comment.date_added }}
</strong>
<br/>
{{ comment.body }}
<br/><br/>
{% endfor %}
{% endif %}
<hr>
<div>Comment and let us know your thoughts</div>
<form method="POST">
{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-primary btn-sm shadow-none" type="submit">Post comment</button>
<button class="btn btn-outline-primary btn-sm ml-1 shadow-none" type="button">Cancel</button>
</form>
{% endfor %}
In models.py, in the comment class, change
user = models.OneToOneField(User, on_delete=models.CASCADE)
to
user = models.ForeignKey(to=User, on_delete=models.CASCADE)
One to one works both ways, user's allowed to only have one comment and a comment can belong to only one user. By changing to one to many via foreignkey you'll preserve the latter and get rid of the former constraint.

Django Update unique modelform field

I have created small stock web app.
I created a stock model with unique part_number field. In my update template I send all item information to be displayed. Then I get an error in the part_number field that it is already there.
How can I avoid this validation for that part_number only?
I mean for same part_number suppose validation will not work. But if I modified to another part_number that already exists I get an error that it's being duplicated.
Model:
class Stock(models.Model):
part_number = models.CharField(max_length=30, blank=False, unique=True)
part_name = models.CharField(max_length=70)
quantity = models.IntegerField(blank=False)
location = models.CharField(max_length=3, blank=True)
model = models.CharField(max_length=40, blank=True, null=True, default="")
min_quantity = models.IntegerField(unique=False, blank=True, default=0)
max_quantity = models.IntegerField(unique=False, blank=True, default=0)
class Meta:
ordering = ['part_number']
def clean(self):
self.part_number = self.part_number.upper()
def __str__(self):
return self.part_number
Form.py:
class StockUpdateModelForm(forms.ModelForm):
class Meta:
model = models.Stock
fields = ['part_name', 'quantity', 'location','part_number']
views.py:
def stock_update_form_view(request, part_id):
item = Stock.objects.get(id=part_id)
item_id = Stock.objects.get(id=part_id).pk
form = StockUpdateModelForm({
'part_number' : item.part_number,
'part_name' : item.part_name,
'quantity' : item.quantity,
'location' : item.location
})
if request.method == 'POST':
form = StockUpdateModelForm(request.POST)
if form.is_valid():
s = Stock.objects.get(pk=item_id)
s.part_name = form.cleaned_data['part_name']
s.part_number = form.cleaned_data['part_number']
s.quantity = form.cleaned_data['quantity']
s.location = form.cleaned_data['location']
print("form is valid")
s.save()
return redirect('/stock/')
return render(request, 'stock/stock_update.html', {'form': form, 'pn': item.part_number})
html:
<form class="bg-light shadow" method="POST">
<div style="margin-left:10%; margin-top:30px">
<h4>Part Number : {{ pn }}</h4>
</div>
<hr style="width:100%">
{% csrf_token %}
<div class="row" style="margin-left:30px; margin-top:40px ">
<div class="col-sm-4" style="margin-left:6%">
{{ form.part_name|as_crispy_field }}
</div>
<div class="col-sm-4" style="margin-left:15%">
{{ form.part_number|as_crispy_field }}
</div>
<div class="col-sm-4" style="margin-left:6%">
{{ form.quantity|as_crispy_field }}
</div>
<div class="col-sm-4" style="margin-left:15%">
{{ form.location|as_crispy_field }}
</div>
<div class="col-sm-4" style="height: 100px; margin-top:30px ; margin-left:6%">
<hr style="width:100%">
<input class="btn btn-primary" type="submit" value="Save"
style="width: 150px;">
</div>
</div>
</form>
try this
if request.method == 'POST':
form = StockUpdateModelForm(request.POST, instance=item)
if form.is_valid():
form.save()

Trying to show latest record - Django

Models
class Category(models.Model):
class Meta():
verbose_name_plural = "Categories"
cat_name = models.CharField(max_length=50)
description = models.TextField()
def get_forums(self):
get_forum = Forum.objects.filter(category=self)
return get_forum
def __str__(self):
return f"{self.cat_name}"
class Forum(models.Model):
class Meta():
verbose_name_plural = "Forums"
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name="forums")
parent = models.ForeignKey('self', blank=True, null=True, on_delete=models.CASCADE)
forum_name = models.CharField(max_length=50)
description = models.TextField()
def __str__(self):
return f"{self.forum_name}"
class Thread(models.Model):
class Meta():
verbose_name_plural = "Threads"
get_latest_by = "date_posted"
forum = models.ForeignKey(Forum, on_delete=models.CASCADE, related_name="threads")
author = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=50)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
def __str__(self):
return f"{self.title} by: {self.author}"
View
class Home(ListView):
model = Category
template_name = 'forums/index.html'
context_object_name = 'category'
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super().get_context_data(**kwargs)
# Add in a QuerySet of all the Cat
context['category'] = Category.objects.all()
return context
HTML
{% block content %}
{% for cat in category %}
<div style="padding-top: 20px;">
<div class="row">
<div class="bg-success rounded-top border border-dark" style="width:100%; padding-left:8px;">
{{ cat.cat_name }}
</div>
</div>
{% for forum in cat.forums.all %}
<div class="row">
<div class="bg-secondary border border-dark" style="width:100%; padding-left:16px;">
{{ forum.forum_name }}
{% for threads in forum.threads.all %}
<div class="float-right" id="latest-post">
<p>{{ threads.title }}</p>
<p> {{ threads.author.username }} </p>
</div>
{% endfor %}
</div>
</div>
{% endfor%}
</div>
{% endfor %}
{% endblock content %}
Problem
I am building a forums and am trying to get my homepage to show the last post in a forum.
I have got it to work to show all threads, but i just want the latest one to show on the latest post div.
I setup the get_latest_by on the Thread model so that it gets the latest one by the time created.
How would i be able to get this to display the latest thread?
You can set a property on the Form model, and then call it in the template.
views.py
class Form(models.Model):
...
#property
def get_newest_thread(self):
return self.threads.all().order_by('date_posted').first()
html
{% with threads=forum.get_newest_thread %}
<div class="float-right" id="latest-post">
<p>{{ threads.title }}</p>
<p> {{ threads.author.username }} </p>
</div>
{% endwith %}