Comments are not saving from frontend in django - javascript

Hi everyone the comments are not working with CBV my form not even saving the comment. here is my code i will love if anyone help me with this.my models.py is
class Product(models.Model):
title = models.CharField(max_length=110)
slug = models.SlugField(blank=True, unique=True)
price = models.DecimalField(decimal_places=2, max_digits=6)
discount_price=models.FloatField(blank=True, null=True)
size = models.CharField(choices=SIZE_CHOICES, max_length=20)
color = models.CharField(max_length=20, blank=True, null=True)
image = models.ImageField(upload_to=upload_image_path)
description = models.CharField(max_length=1000)
featured = models.BooleanField(default=False)
author = models.ForeignKey(User, on_delete=models.CASCADE)
time_stamp = models.DateTimeField(auto_now_add=True)
objects=ProductManager()
def get_absolute_url(self):#i use this in product_list.html to go to detail page
#return "/product/{slug}".format(slug=self.slug)
return reverse("products:detail", kwargs={"slug" : self.slug})
def __str__(self):
return str(self.title)
#property
def name(self): #sometime in html i say name istead of title so to make it work i wrote this
return self.title
def product_pre_save_reciever(sender, instance, *args, **kwargs):#i inherit unique slug generator from utils to here so when i create aa new instance it slug automatically generate. and i i create two t shirts it give a random straing to tshirt 2nd slug
if not instance.slug:
instance.slug=unique_slug_generator(instance)
pre_save.connect(product_pre_save_reciever, sender=Product)
class Comment(models.Model):
product=models.ForeignKey(Product , related_name="comments", on_delete=models.CASCADE)
name = models.CharField(max_length=255)
body=models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '%s - %s'%(self.product.title, self.name)
my forms.py is:
from django import forms
from .models import Comment
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['name', 'body']
widgets ={
'name':forms.TextInput(attrs={'class':'form-control'}),
'body':forms.Textarea(attrs={'class':'form-control'}),
}
the views.py is:
class CommentCreateView(CreateView):
model = Comment
form_class = CommentForm
template_name = 'add-comment.html'
# fields = '__all__'
def form_valid(self, form):
form.instance.product_id = self.kwargs['pk']
return super().form_valid(form)
success_url = reverse_lazy('list')
my add-comment.html is:
{% extends "base.html"%}
{% load crispy_forms_tags%}
{% block content %}
<h2 class="text-center">comment here...</h2>
<div class="col-md-6 offset-md-3">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
{{form|crispy}}
</fieldset>
<!-- <div class="form-group"><button class="btn btn-outline-info" type="submit">Pubmit</button>-->
<!-- </div>-->
<!-- <input type="submit" value="Submit" class="btn btn-secondary">-->
<button class="btn btn-secondary">Add comment</button>
</form>
</div>
{% endblock %}
and my urls.py is:
urlpatterns = [
# path('featured/' , ProductFeaturedListView.as_view()),
#path('featured/<int:pk>' , ProductFeaturedDetailView.as_view()),
path('' , ProductListView.as_view(), name= "list"),
path('new/' , ProductCreateView.as_view() , name="product-create"),
path('<slug:slug>/update/' , ProductUpdateView.as_view() , name="product-update"),
path('<slug:slug>/delete/' , ProductDeleteView.as_view() , name="product-delete"),
#path('product-fbv/' , product_list_view),
#path('product/<int:pk>' , ProductDetailView.as_view()),
path('<slug:slug>/comment' , CommentCreateView.as_view() , name="add-comment"),
path('<slug:slug>' , ProductDetailSlugView.as_view() , name="detail"),
# path('product-fbv/<int:pk>' , product_detail_view),
]
and the error comes when I hit post comment is:

The problem comes from the fact you don't provide any pk keyword argument to your view.
From the urls.py, I can see you have a slug kwargs though. You can then identify the matching product with its slug.
In your views.py, replace:
form.instance.product_id = self.kwargs['pk']
by
form.instance.product = Product.objects.get(slug=self.kwargs['slug'])
Explanation:
Here you want to associate your comment with the matching product. So, for that, you use NameOfModel.objects.get(query), which returns one single instance of your model (here Product), matching the query. In your case the only way to retrieve the object is getting the keyword argument slug from your url and search it on your Product slug field, so here the query is slug=self.kwargs['slug'].

Related

I have a problem in submitting comments to server using json and fetch in django

I am working on a bookstore project using django and javascript. I want to allow user to add comments on each book and send the comment without reloading the page using JSON
html:
<h3 id="authorname">{{book.authorname}}</h3>
<h1 id="bookname"> {{book.name}}</h1>
<p id="slogan">-{{book.slogan}}-</p>
<h2 id="price">Price:- <span>${{book.price}}</span></h2>
<form id="addcomment">
{% csrf_token %}
<input hidden name='thecommentuser' value="{{ request.user.id }}" id="commentsubmitter">
<input hidden name='thecommentbook' value="{{ book.id }}" id="commentbook">
<textarea name='thecomment'id="comment"></textarea>
<input type="submit">
</form>
script:
document.addEventListener('DOMContentLoaded', function() {
document.querySelector('#addcomment').onsubmit = function() {
fetch('/comments', {
method: 'POST',
body: JSON.stringify({
thecomment: document.querySelector('#comment').value,
thecommentuser: document.querySelector('#commentsubmitter').value,
thecommentbook: document.querySelector('#commentbook').value,
})})}});
models.py:
class books(models.Model):
bookuser= models.ForeignKey('User', on_delete=models.CASCADE, default= None, blank=True)
name = models.CharField(max_length=80)
slogan = models.CharField(max_length=200, null=True,
price = models.IntegerField()
authorname= models.CharField(max_length=30)
class comments(models.Model):
comment = models.CharField(max_length= 100)
commentuser = models.ForeignKey('User', on_delete=models.CASCADE, default=None)
commentbook = models.ForeignKey('books', on_delete=models.CASCADE, default=None)
def serialize(self):
return {
'thecomment': self.comment,
'thecommentuser': self.commentuser,
'thecommentbook': self.commentbook
}
urls.py:
urlpatterns = [
path('book/<int:id>', views.book, name='book'),
path('comments', views.addcomments, name='comments')
]
views.py:
from django.views.decorators.csrf import csrf_exempt
from .models import *
from django.contrib.auth.decorators import login_required
import json
def book(request, id):
submitedbook = books.objects.get(id=id)
bkchapters = chapters.objects.filter(chapterbook=submitedbook)
bkrewards = rewards.objects.filter(rewardbook = submitedbook)
return render(request, 'network/book.html', {'book':submitedbook, 'chapters':bkchapters, 'rewards':bkrewards})
#csrf_exempt
#login_required
def addcomments(request):
if request.method == 'POST':
print('posted')
data= json.loads(request.body)
comment = data.get('thecomment', '')
commentuser = data.get('thecommentuser')
commentbook = data.get('thecommentbook', '')
cuser = User.objects.get(id = commentuser)
cbook = books.objects.get(id = commentbook)
thecommentt = comments(
thecomment=comment,
thecommentuser=cuser,
thecommentbook=cbook
)
thecommentt.save()
when I open the comments in the admin page I don't find any submitted data and the page reload upon submitting a comment. the order of print('posted') in views.py isn't displayed to me upon adding a comment and that means that the request isn't sent but I don't know why
this appears to me in the terminal window upon adding the comment:
[30/Oct/2022 01:47:19] "GET /book/1?csrfmiddlewaretoken=9QgGiDOUnVxMlxZQ6UkSmiO4auq5BLojV6iWW55qE9LER929Qj7WB8LVtkBfpnJ4&thecommentuser=1&thecommentbook=1&thecomment=Book HTTP/1.1" 200 14927
I tried to delete if request.method == 'POST': in views and to print in views but nothing changed. Also I tried to console.log('submitted') on submitting the comment but nothing appeared
new update:
I find that the error comes from the browser itself as I find that data is sent upon submitting from another browser so although the two browsers are updated. so how could I solve this?

Django smart selects doesn't work with JS cloning

I'm trying to create a page with ability to add any amount of form-copy.
I use django-smart-selects to make my form's field chained. It works fine if I have only 1 form on page.
Then I'm using javascript to make a function to clone form instance by pressing button and addind new form's ids to these clones.
The problem is when I press "+" button I get new cloned form on page, but chained-selection doesn't work anymore(only first one still works), and it seems that this clone copying all my choices from the firs form and remembering this state.
I see in terminal this response every time I choose any selection in chained fields:
[31/Oct/2022 16:42:27] "GET /chaining/filter/cash_table/LevelOne/flowtype/cash_table/CashFlowPattern/level_one/1/ HTTP/1.1" 200 115
[31/Oct/2022 16:42:29] "GET /chaining/filter/cash_table/LevelOne/flowtype/cash_table/CashFlowPattern/level_one/2/ HTTP/1.1" 200 105
But in cloned forms it doesn't happen.
My Formset is:
forms.py
from django import forms
from .models import CashFlowPattern
from django.forms import modelformset_factory
class CashFlowForm(forms.ModelForm):
class Meta:
model = CashFlowPattern
fields = '__all__'
CashFowFormSet = modelformset_factory(
CashFlowPattern,
fields=(
'flow_type',
'level_one',
'level_two',
'eom',
'amount',
'comment'
),
extra=1
)
views.py
class FormAddView(TemplateView):
template_name = 'cash_table/index.html'
def get(self, *args, **kwargs):
formset = CashFowFormSet(queryset=CashFlowPattern.objects.none())
return self.render_to_response({'formset': formset})
def post(self, *args, **kwargs):
end_of_month = (datetime.datetime.now() + relativedelta(day=31)).strftime('%Y-%m-%d')
formset = CashFowFormSet(data=self.request.POST)
if formset.is_valid():
forms = formset.save(commit=False)
for form in forms:
form.eom = end_of_month
form.user = self.request.user
form.save()
# return redirect(reverse_lazy("bird_list"))
return self.render_to_response({'formset': formset})
template:
<form id="form-container" method="POST">
{% csrf_token %}
{{ formset.management_form }}
<div class="empty-form">
{% for form in formset %}
{{ form.media.js }}
<p>{{ form }}</p>
{% endfor %}
</div>
<button id="add-form" type="button">+</button>
<button type="submit" class="btn btn-primary">Отправить</button>
</form>
<script>
let emptyForm = document.querySelectorAll(".empty-form")
let container = document.querySelector("#form-container")
let addButton = document.querySelector("#add-form")
let totalForms = document.querySelector("#id_form-TOTAL_FORMS")
let formNum = emptyForm.length-1
addButton.addEventListener('click', addForm)
function addForm(e) {
e.preventDefault()
let newForm = emptyForm[0].cloneNode(true) //Clone the form
let formRegex = RegExp(`form-(\\d){1}-`,'g') //Regex to find all instances of the form number
formNum++ //Increment the form number
newForm.innerHTML = newForm.innerHTML.replace(formRegex, `form-${formNum}-`) //Update the new form to have the correct form number
container.insertBefore(newForm, addButton) //Insert the new form at the end of the list of forms
totalForms.setAttribute('value', `${formNum+1}`) //Increment the number of total forms in the management form
}
</script>

Creating Multible IDs for multible Buttons in one <Input> Tag

I'm working on a TicTacToe game using Django/Djangotemplates, Python and a bit Javascript. I've come across a problem tho. i only have one Button which is for-looped 9 times. its ID is its index. Now I'm not certain how to add the {{index}} which i defined in the for loop in the javascript onclick function.
here the html template
<div class="grid-container">
{% for index in object.board %}
<div class="grid-item">
<input onclick="change(button.id)" class="buttonsize btn-outline-purple" type="submit" value="" name="button" id="{{index}}">
</div>
{% endfor %}
</div>
</div>
</article>
</form>
<script>
function change(inputid){
console.log("test")
var elem = document.getElementById(inputid);
if (elem.value=="") elem.value = "X"
}
</script>
here the models.py
class TicTacToe(models.Model):
player1 = models.ForeignKey(User, on_delete=models.CASCADE, default="X", related_name="tictactoe_as_player1")
player2 = models.ForeignKey(User, on_delete=models.CASCADE, default="O", related_name="tictactoe_as_player2")
current_player = models.ForeignKey(User, on_delete=models.CASCADE, related_name="tictactoe_current_player")
title = models.CharField(max_length=100)
board = models.CharField(max_length=9, default="012345678")
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('tictactoe-detail', kwargs={'pk': self.pk})
and here the views.py
class TicTacToeCreateView(LoginRequiredMixin, CreateView):
model = TicTacToe
template_name = 'website/newgame_form.html'
fields = ['player1', 'player2', 'current_player', 'title', 'board']
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
class TicTacToeDetailView(UpdateView):
model = TicTacToe
fields = ['player1', 'player2', 'current_player', 'title', 'board']
def clean(self):
if 'button0' in self.data:
print('button0')
i also got a database but there is really not much in there except the player IDs
Adding index to the onclick should be OK
<input onclick="change({{index}})" class="buttonsize btn-outline-purple" type="submit" value="" name="button" id="{{index}}">

Possible to incorporate select tag in django form?

I have a django form being rendered on an html page, and I have a select dropdown menu which performs a filtering function. I was wondering if it was possible to incorporate this select tag as part of my form? I'd like the select tag to be part of routestep_form.
<center>
<form class ="subtitle" method = 'POST' action="{% url 'buildpage:partrequestinfo' %}" enctype="multipart/form-data">{% csrf_token %}
{{routestep_form.as_p}}
<select name = "myselect" id="id_step" onchange="getOptions(this.value)">
<option value="-----">-----</option>
{% for step in steps %}
<option value="{{ step }}">{{ step }}</option>
{% endfor %}
</select>
<br/><br/>
<select id="id_step_option">
<option value="-----">-----</option>
</select>
<input type='submit' value='Next'/>
</form>
</center>
My Form:
class RouteStepForm(forms.ModelForm):
class Meta:
model = RouteStep
fields = '__all__'
widgets = {
'step': Select,
'step_option': Select,
}
error_messages = {
NON_FIELD_ERRORS: {
'unique_together': "%(RouteStep)s %(description)s are not unique.",
}
}
Views: The other forms are forms I had on the same page, my main focus though is on RouteStepForm.
def partrequestinfo(request):
steps = Step.objects.all()
if not request.user.is_staff or not request.user.is_superuser:
raise Http404
req_form = PartRequestForm(request.POST or None, request.FILES or None)
step_form = StepForm(request.POST or None, request.FILES or None)
stepoption_form = StepOptionForm(request.POST or None, request.FILES or None)
routestep_form = RouteStepForm(request.POST or None, request.FILES or None)
if req_form.is_valid() and step_form.is_valid() and stepoption_form.is_valid() and routestep_form.is_valid():
instance = req_form.save(commit=False)
instance.user = request.user
instance.save()
step = step_form.save(commit=False)
step.save()
stepoption = stepoption_form.save(commit=False)
stepoption.save()
routestep = routestep_form.save(commit=False)
routestep.save()
messages.success(request, "Successfully Created")
return HttpResponseRedirect(instance.get_absolute_url())
else:
context = {
"req_form": req_form,
"step_form": step_form,
"stepoption_form": stepoption_form,
"routestep_form": routestep_form,
"steps": steps,
}
return render(request, "buildpage/partrequestinfo.html", context)
Models:
class Step(models.Model):
name = models.CharField(_('Step Name'), max_length=100, default='')
def __unicode__ (self):
return self.name
class StepOption(models.Model):
step = models.ForeignKey(Step, related_name = 'Step', null = True)
name = models.CharField(_('Step Option'), max_length=100, default='')
def __unicode__ (self):
return self.name + " - " + self.step.name
class RouteStep(models.Model):
step_number = models.PositiveIntegerField(_('Step Number'), default = 0)
step = models.ForeignKey(Step, related_name = 'Step+', null = True)
step_option = models.ForeignKey(StepOption, related_name = 'StepOption', null=True)
def __unicode__ (self):
return self.step_option
Try:
class RouteStepForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(forms.ModelForm, self).__init__(*args, **kwargs)
self.fields['step'].widget.choices=[ query.name for query in Step.objects.all()])
If it does not work, please post your template code that show up.
EDIT
I edit my answer, and also find this helpful.Why do I get an object is not iterable error? and this Getting object not iterable error in django form.
Another solution will be Can not iterate a ChoiceField with Select as widget

Django and Ajax/Javascript

I have the following model layout:
class A(models.model):
options = models.ManyToManyField(OptionSet, blank=True, null=True)
values = models.ManyToManyField(Value, blank=True, null=True)
class OptionSet(models.model):
name = models.TextField(unique=True)
values = models.ManyToManyField(Value)
def __unicode__(self):
return '%s' % self.name
class Value(models.Model):
name = models.TextField()
key = models.ForeignKey(Key, related_name='values')
class Key(models.Model):
name = models.TextField(unique=True)
And my forms.py looks like this:
class A_Form(ModelForm):
values = forms.ModelMultipleChoiceField(queryset=Value.objects.all(), widget=CheckboxSelectMultiple, label="Einzelne Werte", required=False)
options = forms.ModelMultipleChoiceField(queryset=OptionSet.objects.all(), widget=CheckboxSelectMultiple, label="Optionen Sets", required=False)
Template:
<form action="." method="POST">{% csrf_token %}
{{ form.as_table }}
<input type="submit" value="Update"/>
</form>
I use that form with a generic update view!
I'm new to javascript/ajax to be honest never did something in javascript/ajax. What I want to do is on mouseover on the options name it should show all the values for that option set. How would one accomplish this?
You can use jquery's .post() method to send the name of the active option to django script(actually url on server).Then you can find out all the values using queries(I'm assuming you already know how to extract data from models).Then again you can use HttpResponse() to send the calculated values list back to your page.

Categories

Resources