This is my first project in Django. I am trying to save rating in Django database but when I click on radio buttons the value doesn't store in database. I have tried solutions of Stack Overflow previously uploaded but none helped me in resolving my issue. I was firstly using RadioSelect in forms.py but still having the same problem.
Here is the code:
Model.py
class Product(models.Model):
title = models.CharField(max_length=120)
brand = models.CharField(max_length=120,default="None")
model = models.CharField(max_length=120,default="None")
slug = models.SlugField(blank=True, unique=True)
category = models.CharField(max_length=120 , default="Phone")
price = models.DecimalField(decimal_places=2, max_digits=20, default=39.99)
class Rating(models.Model):
product=models.ForeignKey(Product,default=None, on_delete=models.PROTECT)
user=models.ForeignKey(User,default=None, on_delete=models.PROTECT)
rating = models.CharField(max_length=120)
Views.py
def add_rating(request,id):
product = get_object_or_404(Product, pk=id)
pro = Product.objects.get(id=id)
if request.method == "POST":
form = RatingForm(request.POST)
if form.is_valid():
product = form.cleaned_data['product']
user = form.cleaned_data['user']
rating = form.cleaned_data['rating']
product = request.POST.get('product', ''),
user = request.POST.get('user', ''),
rating = request.POST.get('rating', ''),
obj = Rating(product=product, user=user, rating=rating)
obj.save()
context = {'obj': obj}
return render(request, 'product/detail.html',context)
else:
form=RatingForm()
return HttpResponse('Please rate the product')
Forms.py
from django import forms
from .models import Rating
class RatingForm(forms.ModelForm):
class Meta:
model = Rating
fields = ('product', 'user','rating')
template.py
<form method="POST" action="{% url 'add_rating' product.id %}">{% csrf_token %}
<ul class="rate-area" style="display:inline;position:absolute">
<input type="radio" id="5-star" name="rating" value="5" /><label for="5- star" title="Amazing">5 stars</label>
<input type="radio" id="4-star" name="rating" value="4" /><label for="4-star" title="Good">4 stars</label>
<input type="radio" id="3-star" name="rating" value="3" /><label for="3-star" title="Average">3 stars</label>
<input type="radio" id="2-star" name="rating" value="2" /><label for="2-star" title="Not Good">2 stars</label>
<input type="radio" id="1-star" name="rating" value="1" /><label for="1-star" title="Bad">1 star</label>
<button type="submit" value="Rate">Rate</button>
</ul>
</form>
You're using a "CharField" on your model while you should be using a "ChoiceField", a ChoiceField would then become a dropdown select.
It would also be easier to use generic editing views; https://docs.djangoproject.com/en/2.2/ref/class-based-views/generic-editing/
Related
I've created a custom HTML form for my model, just like I want to add a post from the front-end. I already created a page with the name add-post.html
<form method="POST" action="">
{% csrf_token %}
<input name="title" type="text">
<textarea spellcheck="false" name="description"></textarea>
<input type="file" name="image" #change="fileName" multiple />
<select required name="priority">
<option value="Low" selected>Low</option>
<option value="Medium">Medium</option>
<option value="High">High</option>
</select>
<input type="checkbox" name="on_hold">
<button type="submit">Add ToDo</button>
</form>
Here's my model.py
class Todo(models.Model):
title = models.CharField(max_length=100)
image = models.ImageField(null=True, blank=True, upload_to='todo/images/')
description = RichTextField()
Low, Medium, High = 'Low', 'Medium', 'High'
priorities = [
(Low, 'Low'),
(Medium, 'Medium'),
(High, 'High'),
]
priority = models.CharField(
max_length=50,
choices=priorities,
default=Low,
)
on_hold = models.BooleanField(default=False)
No, I want to use the above custom HTML form to post data and save it to this model database. instead of using {% form.as_p %}
And I also created a particular page to update this post from the front-end but don't know how to make it work.
Can you please guide me on how can I save data from the custom form and also update it from the custom form?
Appreciate your response :)
#Mubasher Rehman - You are almost there
forms.py
class TodoCreationForm(forms.ModelForm):
class Meta:
model = Todo
fields = ('title','image','description','priorities','priority','on_hold',)
views.py
from django.contrib.messages.views import SuccessMessageMixin
from django.views.generic import CreateView
class CreatProduct(SuccessMessageMixin,CreateView):
model = Todo
form_class = TodoCreationForm
template_name = "add_post.html"
success_message = "Todo was created successfully"
error_message = "Error saving the Todo, check fields below."
add_post.html
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{form.as_p}}
<button type="submit" class="btn btn-primary">Submit</button>
</form>
#Mubasher Rehman - I fought this problem myself for awhile and finally found a solution. My situation was much different than yours, but try this:
In your views.py overwrite the form_valid method like so:
def form_valid(self, form):
if self.request.POST:
if form.is_valid():
t= Todo.objects.create(title='title', image='image', description='description', priority='priority', on_hold='on_hold')
t.save()
return super(ModelView, self).form_valid(form)
'''Models Code'''
# Product Model
class Products(models.Model):
name = models.CharField(max_length=50)
img = models.ImageField(upload_to='productImage')
CATEGORY = (
('Snacks','Snacks'),
('Juice','Juice'),
)
category = models.CharField(max_length=50, choices=CATEGORY)
description = models.TextField()
price = models.FloatField()
# Rating Model
class Rating(models.Model):
product = models.ForeignKey(Products, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
stars = models.IntegerField(validators=[MinValueValidator(1),MaxValueValidator(5)], blank=True, null=True)
comment = models.TextField(blank=True,null=True)
''' Views Code '''
class ProductListView(ListView):
model = Products
template_name = 'products.html'
context_object_name ='Products'
class ProductDetailView(LoginRequiredMixin,DetailView):
login_url = '/accounts/login'
model = Products
# Using this function I want to take the rating and comment, but how can I access the cuurent object for which the comment and rating is being send by the user.
def review(request,slug):
star=request.POST.get('rating')
comment=request.POST.get('comment')
user = request.user
productId = request.POST.get('productsid') # How to get the Product
product = Products.objects.get(id=productId)
review = Rating(product=product,user=user,stars=star,comment=comment)
review.save()
return redirect('/')
# Urls code
urlpatterns = [
path('',views.home,name='Home'),
path('products',ProductListView.as_view(),name='Products'),
path('product/<int:pk>',ProductDetailView.as_view(),name='Product-Details'),
path('contact',views.contact,name='Contact'),
path('review',views.review,name='review')
#Templates Code
<form method="POST" action="review">
{% csrf_token %}
<input type="hidden" id="rating-value" name="rating">
<textarea style="margin-top:5px;" class="form-control" rows="3" id="comment" placeholder="Enter your review" name="comment"></textarea>
<button type="submit" style="margin-top:10px;margin-left:5px;" class="btn btn-lg btn-success">Submit</button>
</form>
How to fetch the current object from the deatailed view page in the review function?
I have added the code here. In Product detailed view page it is rendering the page through which I want to take rating and comment for the product . Is there any other way through which I can get the product, user , star, and rating field value and store it in the data base?
I can point out some ways to retrieve the product_id in your review function.
First approach:
You can pass the product_id as a URL parameter. In this case, I hope the review view is called from the product detail page.
So, your url should be something like:
path('review/<int:product_id>', views.review, name="review),
Your view:
def review(request, *args, **kwargs):
star=request.POST.get('rating')
comment=request.POST.get('comment')
user = request.user
productId = kwargs.get('product_id') # change is here
product = Products.objects.get(id=productId)
review = Rating(product=product,user=user,stars=star,comment=comment)
review.save()
return redirect('/')
Your template:
<form method="POST" action="{% url 'review' object.pk %}">
{% csrf_token %}
<input type="hidden" id="rating-value" name="rating">
<textarea style="margin-top:5px;" class="form-control" rows="3" id="comment" placeholder="Enter your review" name="comment"></textarea>
<button type="submit" style="margin-top:10px;margin-left:5px;" class="btn btn-lg btn-success">Submit</button>
</form>
In the template, the object is the object_name you have given to the product object. You can change the object name by adding:
context_object_name = product
in your ProductDetailView.
Second approach:
Pass the product_id as a form data. You can create a hidden input in your template that will contain the product_id as value. For example:
In your template:
<form method="POST" action="review">
{% csrf_token %}
<input type="hidden" id="rating-value" name="rating">
<input type="hidden" name="product_id" value="{{ object.pk }}"> # add a hidden input field
<textarea style="margin-top:5px;" class="form-control" rows="3" id="comment" placeholder="Enter your review" name="comment"></textarea>
<button type="submit" style="margin-top:10px;margin-left:5px;" class="btn btn-lg btn-success">Submit</button>
</form>
Where object is what I mentioned previously.
Then you can retrieve the product_id in view as:
def review(request,slug):
star=request.POST.get('rating')
comment=request.POST.get('comment')
user = request.user
productId = int(request.POST.get('product_id')) # here
product = Products.objects.get(id=productId)
review = Rating(product=product,user=user,stars=star,comment=comment)
review.save()
return redirect('/')
I'm working on a subscription project that allows user select multiple services using checkbox and then calculate the total price for these services(something like selecting multiple mails from your mail account), I have these in the HTML and Js code but I wan to be able to store each selected services to the DB, please how can I archive this
<form action="{% url 'sub:basic_starter' %}" id="subscription" method="post">
{% csrf_token %}
<fieldset>
<legend><h5><strong>Business Type: </strong> New Business </h5> </legend>
<label>Brand Value Design: N6,180.00
<input type="checkbox" value=" 6179.50" name="services" id="bs1" onclick="subscribe())">
</label><br><br>
<label>Business Development: N6,180.00
<input type="checkbox" value="6180.00" name="services" id="bs2" onclick="subscribe())">
</label><br><br>
<label>Website Design & Dev: N6,180.00
<input type="checkbox" value=" 6180.00" name="services" id="bs3" onclick="subscribe())">
</label><br><br>
<label>Mobile Application : N6,180.00
<input type="checkbox" value="6180.00" name="services" id="bs4" onclick="subscribe())">
</label><br><br>
<label>Maintenance(Host & Domain): N5,450.00
<input type="checkbox" value="5450.00" name="services" id="bs5" onclick="subscribe())">
</label><br><br>
<label>Social Media Management:
<input type="checkbox" value="" name="services" id="bs6" onclick="subscribe())">
</label><br><br>
<input type="text" readonly="readonly" id="total" value="N0.00" ><script>document.getElementById('total').innerHTML=price;</script><br><br>
<input type="submit" value="Subscribe" class="btn btn-success"></a></button><br>
</fieldset>
</form>
</div>
JS
function subscribe(){
let input = document.getElementsByName('services'),
total = 0.00,
form = document.getElementById('subscription');
for (let i = 0; i < input.length; i++) {
if(input[i].checked){
total += parseFloat(input[i].value)
let price = 'N' + total
}
}
document.getElementById('total').value = total.toFixed(3)
}
document.getElementById('subscription').addEventListener('change', subscribe)
Views.py
#login_required
def subscribe(request):
service_list = []
if request.method == 'POST':
sub_form = MembershipForm(request.POST)
if sub_form.is_valid() and sub_form.cleaned_data:
service_list.append(sub_form.data['service_name'])
sub_form.save()
else:
sub_form =MembershipForm()
return render(request, 'sub/subscribe_form.html',{'sub_form':
sub_form})
Url
path('sub', views.subscribe, name='subscribe'),
Forms
class MembershipForm(forms.ModelForm):
class Meta:
model = Services
fields = ('service_name', 'price',)
Models
class Services(models.Model):
package_name = models.CharField(max_length=100)
category = models.CharField(max_length=200)
service_name = models.CharField(max_length=250)
price = models.DecimalField(max_digits=9, decimal_places=2)
def __str__(self):
return self.service_name
class Meta:
unique_together = ('package_name', 'service_name')
class CompanySubscription(models.Model):
company_name = models.ForeignKey(CompanyProfile,
on_delete=models.CASCADE)
services = models.ForeignKey(Services, on_delete=models.CASCADE)
duration = models.CharField(max_length=50)
timestamp= models.DateTimeField(auto_now=True)
def __str__(self):
return self.company_name
If you want to get all checked checkbox value, you have to write below in your view...
#login_required
def subscribe(request):
service_list = []
if request.method == 'POST':
sub_form = MembershipForm(request.POST)
if sub_form.is_valid() and sub_form.cleaned_data:
services_price_list = request.POST.getlist('services[]')
service_list.append(sub_form.data['service_name'])
services_obj = sub_form.save(commit=False)
services_obj.price = sum(services_price_list)
services_obj.save()
else:
sub_form =MembershipForm()
return render(request, 'sub/subscribe_form.html',{'sub_form':
sub_form})
I'm trying to upload multiple images with one single field, in a Django application.
How to do this?
The following files are involved:
upload.html:
<form action="#" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="text" name="image_id" placeholder="Image Id">
<input type="file" name="file" multiple>
<button type="submit"> Upload </button>
</form>
Here, the single field image_id is meant to hold 5 images.
views.py:
def multi_image(request):
if request.method == 'POST':
img_id = request.POST.get('image_id')
file = request.FILES.getlist('file')
data_save = Res(image_id = img_id )
data_save.save()
filter_data = Res.objects.filter(image_id= img_id)
if len(filter_data) > 0:
for i in file:
print(i)
Res.objects.create(image= i)
return render(request, 'upload.html', {})
models.py:
class Res(models.Model):
image_id= models.CharField(max_length=10, blank=True, null=True)
image = models.FileField(upload_to='images', blank=True, null=True)
forms.py:
class FileForm(forms.Form):
class Meta:
model = Res
fields = '__all__'
I'm having an issue, what I need is to save a part number into a database table. So everytime a user enters the SOSS it should be save in my table. This is my code but is not saving anything, not sure what I'm doing wrong.
manifiestos.html
<form action="{% url 'manifiestos' %}" method="post"> {% csrf_token %}
<p><label for="date"> Date:</label> <input type="text" name="date" value={% now "Y-m-d" %} /> </p>
<p><label for="soss"> SOSS:</label> <input type="text" name="soss" id="soss" /> </p>
<input type="submit" value="Submit" />
</form>
models.py
class manifiestos_bts(models.Model):
soss = models.CharField(max_length=50)
date = models.DateTimeField(null=True, blank=True)
user = models.CharField(max_length=50)
forms.py
class ManifiestosForm(forms.Form):
soss = forms.CharField()
date = forms.DateTimeField()
user = forms.CharField()
html_views
#login_required(login_url='/msr/login')
def manifiestos(request):
if request.method == 'POST':
form = ManifiestosForm(request.POST)
if form.is_valid():
soss = request.POST.get('soss', '')
date = request.POST.get('date', '')
manifiestos_obj = manifiestos_bts(soss= soss, date= date)
manifiestos_obj.save()
return HttpResponseRedirect(reverse('manifiestos'))
else:
form = ManifiestosForm()
return render(request, 'manifiestos.html', {'form': form})
urls.py
url(r'^manifiestos$', html_views.manifiestos, name='manifiestos'),
Thanks for your time :)
If you need more details just let me know.
Your form.is_valid() will fail because you are not passing user from your template. Either remove it from ManifiestosForm or pass it from manifiestos.html