Django 5 star rating system is not saving reviews and rating - python

I build a model for user reviews and rating. And made the form for my model , then I call the form in my views . When i click on button from detail page to get the "rate.html" it get me there but did not save the data from there and give me this error .
IntegrityError at /product/new-shoes/rate/
NOT NULL constraint failed: products_review.user_id
my models.py is:
class Review(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
product = models.ForeignKey(Product , on_delete=models.CASCADE)
date = models.DateTimeField(auto_now_add=True)
text = models.TextField(max_length=3000 , blank=True)
rate = models.PositiveSmallIntegerField(choices=RATE_CHOICES)
likes= models.PositiveIntegerField(default=0)
dislikes = models.PositiveIntegerField(default=0)
def __str__(self):
return self.user.full_name
my forms.py is:
class RateForm(forms.ModelForm):
text = forms.CharField(widget=forms.Textarea(attrs={'class':'materialize-textarea'}),required=False)
rate = forms.ChoiceField(choices=RATE_CHOICES, widget=forms.Select(),required=True)
class Meta:
model = Review
fields= ('text', 'rate')
my views.py is:
class RateView(CreateView):
form_class = RateForm
template_name = 'rate.html'
def form_valid(self, form):
form.instance.product = Product.objects.get(slug=self.kwargs['slug'])
return super().form_valid(form)
def get_success_url(self):
return reverse('products:detail', kwargs={'slug': self.object.product.slug})
and my rate.html is:
{% extends "base.html"%}
{% block content %}
<form method="POST" action="" role="form" class="col s12">
{% csrf_token %}
<div class="input-field col s12">
{{ form.rate }}
</div>
<div class="input-field col s12">
{{ form.text }}
<label for="textarea1">Opinion</label>
</div>
<button type="submit" name="action" class="waves-effect waves-light btn"><i class="material-icons left">star</i>Rate</button>
</form>
{% endblock %}
my urls.py for the view is:
path('<slug:slug>/rate/', RateView.as_view(), name='rate-product1'),

The error message is telling you that the user field is not being set. You can do this in the form_valid function:
def form_valid(self, form):
...
form.instance.user = self.request.user
form.instance.product = Product.objects.get(slug=self.kwargs['slug'])
...
return super().form_valid(form)

Try to use this :-
class Review(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
product = models.ForeignKey(Product , on_delete=models.CASCADE,null=True)
date = models.DateTimeField(auto_now_add=True)
text = models.TextField(max_length=3000 , blank=True)
rate = models.PositiveSmallIntegerField(choices=RATE_CHOICES)
likes= models.PositiveIntegerField(default=0)
dislikes = models.PositiveIntegerField(default=0)
def __str__(self):
return self.user.full_name
What i have changed :-
I have set null = True in your product variable, which is with ForeignKey

Related

Unable to Post comments to blog post with Django

I am creating a blog for a project and I am having problem getting my comments to post to the back end.
My code is as follows:
models.py
from django.contrib.auth.models import User
from products.models import Category
class Post(models.Model):
"""Model to create blog posts"""
author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
title = models.CharField(max_length=250)
body = models.TextField(blank=True, null=True)
image = models.ImageField(blank=True, null=True)
created_on = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-created_on']
def __str__(self):
return self.title
class Comment(models.Model):
"""Model to handle user comments"""
author = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, related_name='comments', on_delete=models.CASCADE)
body = models.TextField()
created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-created']
def __str__(self):
return self.body[0:50]
forms.py
from .models import Post, Comment
class PostForm(ModelForm):
"""
Form to allow site owner to create a new blog post
"""
class Meta:
model = Post
fields = ['category', 'title', 'body', 'image']
class CommentForm(ModelForm):
"""Form to handle user comments"""
class Meta:
model = Comment
fields = ('body',)
views.py
def add_comment(request):
"""Method to add comments to a blog post"""
post = get_object_or_404(Post, post_id)
comments = post.comments.all()
new_comment = None
if request.method == 'POST':
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.post = post
new_comment.save()
else:
comment_form = CommentForm()
template = 'blog/post_detail.html'
context = {
'post': post,
'comments': comments,
'new-comment': new_comment,
'comment_form': comment_form,
}
return render(request, template, context)
urls.py
from . import views
urlpatterns = [
path('', views.view_blog, name="blog"),
path('<int:post_id>/', views.post_detail, name="post_detail"),
path('add_post/', views.add_post, name="add_post"),
path('edit_post/<int:post_id>/', views.edit_post, name="edit_post"),
path('delete/<int:post_id>/', views.delete_post, name="delete_post"),
path('add_comment/', views.add_comment, name="add_comment"),
path('delete/comment/<int:comment_id>/', views.delete_comment, name="delete_comment"),
]
Could anyone see where I am going wrong please? I have been playing around and getting different type of name and value error and am not getting any further forward.
Current template
<div id="comment-input">
{% if request.user.is_authenticated %}
<form action="{% url 'add_comment' %}" method="POST">
{% csrf_token %}
<div class="w-100 mb-2">
{{ comment_form | crispy }}
<button class="form-control btn btn-black border border-black rounded-0" type="submit">Submit
</button>
</div>
{% endif %}
</div>
<div class="comment-wrapper">
{% for comment in post.comments.all %}
<div id="comment-details">
<div id="comment-author">
{{comment.author}} - {{comment.created|timesince}} ago
</div>
<div id="comment-body">
{{comment.body}}
</div>
</div>
<div id="delete-comment">
{% if request.user == comment.author %}
Delete Comment
{% endif %}
</div>
<hr>
{% endfor %}
</div>

how to correctly saving a profile instance in django

I have a problem with creating a profile instance in Django. when I try to update a profile the images of the profile don't save in the database My guess is that the form.save(commit=False) does not upload the photo nor update the field as it should but I do not understand why :
here is my code:
models.py
class Profile(models.Model):
user = models.OneToOneField(User, primary_key =True, on_delete=models.CASCADE, related_name= 'profile')
image = models.OneToOneField(UserImage, on_delete=models.SET_NULL, null=True, blank=True)
phone_number = models.CharField(max_length=50, null = True, blank = True)
followers = models.ManyToManyField(User, related_name='follower', blank=True)
following = models.ManyToManyField(User, related_name='following', blank=True)
biography = models.TextField(max_length=250, null=True, blank=True)
class UserImage(models.Model):
avatar = models.ImageField(blank=True, null=True,upload_to='avatar_pic')
header_image = models.ImageField(blank=True, null=True,upload_to='header_pic')
forms.py
class ProfileForm(ModelForm):
class Meta:
model = Profile
fields = (
'phone_number',
'biography',
)
class ImageProfileForm(ModelForm):
class Meta:
model = UserImage
fields = (
'avatar',
'header_image',
)
views.py
#login_required
def CompleteSignUp(request):
if request.method == 'POST':
profile_form = ProfileForm(request.POST,request.FILES ,instance=request.user.profile)
image_profile_form = ImageProfileForm(request.POST, instance=request.user.profile.image)
if profile_form.is_valid() and image_profile_form.is_valid():
profile = profile_form.save(commit=False)
images = image_profile_form.save()
profile.user = request.user
profile.social = social
profile.image = images
profile_form.save()
return redirect('blog:Home')
else:
profile_form = ProfileForm(
initial={
'phone_number':request.user.profile.phone_number,
'biography':request.user.profile.biography
}
)
if request.user.profile.image:
image_profile_form = ImageProfileForm(
initial={
'avatar':request.user.profile.image.avatar,
'header_image':request.user.profile.image.header_image
}
)
else:
image_profile_form = ImageProfileForm()
return render(request, 'user/createprofile.html', {'form_p': profile_form, 'form_i': image_profile_form})
templates
{% block content %}
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div>
{{ form_p.biography }}
biography
</div>
<div>
{{ form_p.phone_number }}
phone_number
</div>
<div>
{{ form_i.avatar }}
avatar
</div>
<div>
{{ form_i.header_image }}
header
</div>
<br>
<input type="submit" value="Register">
</br>
</form>
{% for field in form_s %}
{% for error in field.errors %}
<p style="color: rgba(255, 0, 0, 0.678)">{{ error }}</p>
{% endfor %}
{% endfor %}
{% endblock %}
profile save but the image of the profile doesn't save what's my fault.
...
Change:
profile.user = request.user
profile.social = social
profile.image = images
profile_form.save()
To:
profile.user = request.user
profile.social = social
profile.image = images
profile.save() # Use this
You need to save profile instead of the form with commit=False, because you did custom stuff to profile.

ValueError Cannot assign "<QuerySet [<Product:name>]

I am a student learning Django. I want to implement so that I receive the product code in the order(join model) DB when ordering a product, but it is difficult because I keep getting an error like the title. I think I will die because it hasn't been solved for too long.
When I use product.object.all(), all the query sets are loaded, and even when I use a filter, an error occurs. How can I solve this problem? It would be such an honor if you could reply.
Error Message
ValueError at /join/element_detail/ Cannot assign "<QuerySet
[<Product: 학잠>, <Product: 헤라 블랙쿠션>, <Product: 종근당 활력 비타민B>, <Product:
코디 순수 3겹데코>, <Product: 다이어리>, <Product: 화이트 스탠드 조명>, <Product: 파이썬 웹
프로그래밍 교재>, <Product: 나이키 후드집업>]>": "Join.product_code" must be a
"Product" instance.
join / views.py
join.product_code = product
This part appears to be the problem.
models.py
class Product(models.Model):
product_code = models.AutoField(primary_key=True)
username = models.ForeignKey(Member, on_delete=models.CASCADE, db_column='username')
category_code = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True, related_name='products')
name = models.CharField(max_length=200, db_index=True)
slug = models.SlugField(max_length=200, db_index=True, unique=False, allow_unicode=True)
image = models.ImageField(upload_to='products/%Y/%m/%d', blank=True)
benefit = models.TextField()
detail = models.TextField()
target_price = models.IntegerField()
start_date = models.DateField()
due_date = models.DateField()
class Meta:
ordering = ['product_code']
index_together = [['product_code', 'slug']]
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('zeronine:product_detail', args=[self.product_code, self.slug])
class Join(models.Model):
join_code = models.AutoField(primary_key=True)
username = models.ForeignKey(Member, on_delete=models.CASCADE, db_column='username')
product_code = models.ForeignKey(Product, on_delete=models.CASCADE, db_column='product_code')
part_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.join_code)
class Meta:
ordering = ['join_code']
My guess is that there is something wrong with this part.(join/views.py)
I think something went wrong in the process of receiving the product, but I don't know how.
join/views.py
def element_detail(request):
designated_object = Designated.objects.all()
element_object = Element.objects.all()
value_object = Value.objects.all()
product = Product.objects.all()
if request.method == "POST":
join = Join()
join.product_code = product
join.username = request.user
join.part_date = timezone.now()
join.save()
return render(request, 'zeronine/list.html')
return render(request, 'zeronine/detail.html', {'designated_object': designated_object,
'element_object': element_object,
'value_object': value_object})
zeronine/views.py
def product_in_category(request, category_slug=None):
current_category = None
categories = Category.objects.all()
products = Product.objects.all()
if category_slug:
current_category = get_object_or_404(Category, slug=category_slug)
products = products.filter(category_code=current_category)
return render(request, 'zeronine/list.html', {'current_category': current_category,
'categories':categories,
'products':products})
def product_detail(request, id, product_slug=None):
current_category = None
categories = Category.objects.all()
products = Product.objects.all()
product = get_object_or_404(Product, product_code=id, slug=product_slug)
designated_object = Designated.objects.filter(rep_price='True')
element_object = Element.objects.all()
value_object = Value.objects.all()
return render(request, 'zeronine/detail.html', {'product':product,
'products':products,
'current_category': current_category,
'categories':categories,
'designated_object': designated_object,
'element_object':element_object,
'value_object':value_object})
zeronine/detail.html
<form method="POST" style="margin-left: 110px;" action="{% url 'zeronine:element_detail' %}">
<div class="form-group row">
<label for="value_code" class="col-sm-2 col-form-label"><b>옵션</b></label>
<div class="col-sm-5">
<select type="text" class="form-control" name="value_code" id="value_code">
{% for value in value_object %}
{%if value.product_code == product %}
<option value="{{value.value_code}}">{{value.name}}</option>
{% endif %}
{% endfor %}
</select>
</div>
</div>
{% csrf_token %}
{% if not user.is_authenticated %}
<a onclick="alert('로그인 후 참여가 가능합니다.');" style="cursor:pointer;">
<button type="submit" style="background:black; border-color:black;" class="btn btn-primary"> 참여하기</button></a>
<a onclick="alert('로그인 후 찜하기가 가능합니다.');" style="cursor:pointer;">
<button type="submit" style="background:white; color:black; border-color:black;" class="btn btn-primary">찜하기</button></a>
{% else %}
<a onclick="alert('{{ product.name }} 공동구매 참여가 완료되었습니다.');" style="cursor:pointer;">
<button type="submit" action="{% url 'zeronine:element_detail' %}" style="background:black; border-color:black;" class="btn btn-primary"> 참여하기</button></a>
<a onclick="alert('{{ product.name }} 상품을 찜했습니다.');" style="cursor:pointer;">
<button type="submit" style="background:white; color:black; border-color:black;" class="btn btn-primary">찜하기</button></a>
{% endif %}
</form>
def element_detail(request):
designated_object = Designated.objects.all()
element_object = Element.objects.all()
value_object = Value.objects.all()
product = Product.objects.all()
if request.method == "POST":
product_id = request.POST.get('value_code') # new
product = Product.objects.get(product_code=product_id) # new
# Or
#product_ids = request.POST.getlist('value_code')
#products = Product.objects.filter(product_code__in=product_ids)
#loop all products and save example;
#for product in products:
# join = Join()
# join.product_code = product
# join.username = request.user
# join.part_date = timezone.now()
# join.save()
join = Join()
join.product_code = product
join.username = request.user
join.part_date = timezone.now()
join.save()
return render(request, 'zeronine/list.html')
Edited to include multiple values from template, I'm assuming of course.

django, does not display the avatar in the comments

I extended standart django user model by one-to-one field. Made news block, and added comments there. In comments i cant display user avatar from UserProfile model, cause dont understand how correctly ask database for it D;. Here my code:
main/models.py
from django.db import models
from django.utils import timezone
from django.contrib import auth
from django.contrib.auth.forms import User
from django.shortcuts import render, redirect
from profiles.models import UserProfile
# Create your models here.
class News(models.Model):
news_title = models.CharField(max_length=250)
news_body = models.TextField(max_length=2000, blank=True)
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
image = models.FileField()
published_date = models.DateTimeField(blank=True, null=True)
def publish(self, request):
self.published_date = timezone.now()
self.save()
return redirect('index')
def __str__(self):
return self.news_title
class Comment(models.Model):
news = models.ForeignKey('main.News', related_name='comments',
on_delete=models.CASCADE)
author = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
approved_comment = models.BooleanField(default=False)
def approve(self):
self.approved_comment = True
self.save()
def __str__(self):
return self.text
profiles/models.py
class UserProfile(models.Model):
JEW_CHOICE = (
('Да', 'Да'),
('Нет', 'Нет'),
)
MF_CHOICE = (
('М', 'М'),
('Ж', 'Ж')
)
user = models.OneToOneField(User, on_delete=models.CASCADE)
country = models.CharField(max_length=100, default='', blank=True)
city = models.CharField(max_length=100, default='', blank=True)
description = models.CharField(max_length=500, default='', blank=True)
website = models.URLField(default='', blank=True)
avatar = models.ImageField(default='', blank=True)
gender = models.CharField(max_length=100, choices = MF_CHOICE, default = 'М', blank=True)
jew = models.CharField(max_length=100, choices = JEW_CHOICE, default = 'Да', blank=True)
def __str__(self):
return self.user.username
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.get_or_create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.userprofile.save()
#property
def avatar_url(self):
if self.avatar and hasattr(self.avatar, 'url'):
return self.avatar.url
main/views.py (meme_detail is the view, where should be comments with user info)
def meme_detail(request, pk):
news = get_object_or_404(News, pk=pk)
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.author = request.user
comment.news = news
comment.save()
return redirect('main:meme_detail', pk=news.pk)
else:
form = CommentForm()
return render(request, 'main/meme_detail.html', {'news': news, 'form': form,})
meme_detail.html (news template with comments)
{% extends 'main/base.html' %}
{% block body %}
<h2>{{news.news_title}}</h2>
<img src='{{news.image.url}}' name='image' width='500px;'><br>
{{news.news_body}} <br><br>
<div class="row">
<div class="col">
<b>{{news.author}}</b>
</div>
<div class="col">
<i>{{news.published_date}}</i>
</div>
</div>
<div class="underline"></div>
<h3>Комментарии:</h3><br>
{% for comment in news.comments.all %}
<div class="row">
<div class="col-"><img src="{{ userprofile.avatar.url }}" alt="user-avatar" width="100px" height="100px"></div>
<div class="col">{{ comment.text }}</div>
</div>
<div class="row">
<div class="col"><strong>{{ comment.author }}</strong></div>
<div class="col">{{ comment.created_date}}</div>
</div>
<div class="underline"></div>
<br>
{% empty %}
<p>Пока ещё нет комментариев :(</p>
{% endfor %}
{% if request.user.is_authenticated %}
<div class="row">
<form method="POST">
{% csrf_token %}
{{form.text}}<br><br>
<a class="btn btn-success" href="{% url 'main:meme_detail' pk=news.pk %}"><button class='btn btn-success'>Добавить коммент! </button></a>
</form>
</div>
{% else %}
<i>Вы не можете писать комментарии, необходимо зарегистрироваться!</i>
{% endif %}
{% endblock %}
So, in this template, where "userprofile.avatar.url" should be object reference on User avatar. I tryed a lot of things, but it always the same:not displaying
You should do:
<img src="{{ comment.author.userprofile.avatar.url }}" alt="user-avatar" width="100px" height="100px">
Your comment has a foreign key to User (author), and User has a one to one field to UserProfile, which is the one that has the avatar attribute.
Also another tip:
You shouldn't really reduce the image in CSS (width: 100px; height: 100px;), but instead use a tool that allows you to create thumbnails of images. I use sorl-thumbnail and can't recommend it enough.
The reason is that if every user uploads a 1000x1000 image, you are downloading those big images that you don't really need, hence your site will be slower.
Maybe you should try accesing the User object in the template, not the Userprofile.
<img src="{{ user.userprofile.avatar.url }}" ...

How to have my users add song to an album in django

I am trying to be able to add songs through a form but keep getting
NOT NULL constraint failed: post_song.album_id.
As of right now I can only add songs ramdomly and they aren't connected to the original album.
from django.db import models
from django.core.urlresolvers import reverse
from django.conf import settings
from django.contrib.auth.models import User
class Album(models.Model):
creator = models.CharField(max_length=250)
album_name = models.CharField(max_length=250)
album_photo = models.FileField()
author = models.ForeignKey(User, blank=True, null=True, related_name ='album_post')
category = models.ManyToManyField(Category)
def get_absolute_url(self):
return reverse('post:detail', kwargs={'pk': self.pk})
def __str__(self):
return self.creator + ' - ' + self.album_name
class Song(models.Model):
album = models.ForeignKey(Album, on_delete=models.CASCADE, null=True)
song_name= models.CharField(max_length=1000)
def __str__(self):
return self.song_name
def get_absolute_url(self):
return reverse('post:detail', kwargs={'pk': self.pk})
views.py
class SongAdd(CreateView):
model = Song
fields = ['song_name']
def form_valid(self, form):
form.instance.album_id = self.request.GET.get('album_pk')
return super(SongAdd, self).form_valid(form)
details page
{% block body %}
<div class="container-fluid">
<div class="row">
<div class="col-sm-12 col-md-7">
<div class="panel panel-default">
<div class="panel-body">
<form class="form-horizontal" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{% include 'post/form-template.html' %}
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-success">Submit</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
In your view, you are missing the album field. The form does not know what album you want to associate the song to.
Try this:
views.py
class SongAdd(CreateView):
model = Song
fields = ['song_name']
def form_valid(self, form):
album = Album.objects.get(pk=album_id_variable)
form.instance.album = album
return super(SongAdd, self).form_valid(form)
Make sure album_id_variable is a valid album id.

Categories