Django and Ajax/Javascript - 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.

Related

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>

How to check if an input value is exists and validate if yes in Django

I made a text input filed with jquery autocomplete where I query the users. So if I start typing the name of a user it shows the related users. It works fine but I like to avoid
that if the user like not to choose from the pupped up list and possibly type all the name and it has a mistake.
So I like to make a function that checks if the added value of the field is equals with any of the users in the database. How to do that?
html
<input type="text" class="form-control" placeholder="Type name here" name="kap_bar_01" id="kap_bar_01">
<script>
$(function() {
var names = [
{% for u in related_users %}
"{{ u.user.last_name }} {{ u.user.first_name }}",
{% endfor %}
];
$( "#kap_bar_01" ).autocomplete({
source: names
});
});
</script>
models.py
class Kapcsolodasok(models.Model):
def __str__(self):
return str(self.user_name)
user_name = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
date = models.DateField(auto_now_add=True, auto_now=False, blank=True)
kap_bar_01 = models.TextField(max_length=200)
views.py
def kapcsolodasok(request):
profile = Profile.objects.get(user=request.user)
related_users = Profile.objects.filter(projekt=profile.projekt)
context = {
'related_users': related_users,
'profile': profile,
}
#lots of stuffs here
return render(request, 'stressz/kapcsolodasok.html', context)
Thank you in advance!
from django.contrib.auth.models import User
userList = User.objects.values()
The above code will get the usernames as list and loopover to check the username entered.But i think you want it to be checked in realtime so you have to use channels or ajax etc.Otherwise just pass the username value as url url/ and check it

Comments are not saving from frontend in django

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'].

Dynamically update Django form field options using Ajax to GET new queryset

I'm new to coding and django and I'm struggling to find the solution to the following problem having reviewed the answers I've found.
Im creating a search form with multiple fields. When the user selects the first field category (and before hitting search) I would like to dynamically change the queryset for the second field sub_category such that only related values are shown.
I have models.py as follows:
class Product(models.Model):
category = models.ForeignKey("Category")
sub_category = models.ForeignKey("SubCategory")
class Category(models.Model):
name = models.CharField(max_length=256)
class SubCategory(models.Model):
category = models.ForeignKey("Category")
name = models.CharField(max_length=256)
And my forms.py includes:
class BasicSearchForm(forms.Form):
category = forms.ModelChoiceField(
label='Category',
queryset=Category.objects.all(),
to_field_name="name",
empty_label=None,
initial="Red")
sub_category = forms.ModelMultipleChoiceField(
required=False,
label='Type',
queryset= SubCategory.objects.all(),
to_field_name="name",
widget=forms.Select)
And my views.py includes:
def search(request):
if request.method == 'POST':
form = BasicSearchForm(request.POST)
if form.is_valid():
category = form.cleaned_data['category']
sub_category = form.cleaned_data['sub_category']
return render(request, 'myapp/search.html', {'form': form})
else:
form = BasicSearchForm()
return render(request, 'myapp/search.html', {'form': form})
And finally the search.html includes:
<form class="search-form" role="search" action="/search/" method="get">
{{ form }}
<input type="submit" value="Search" />
</form>
I've played around with a few answers but nothing seems to work. I'd really appreciate some help. Thanks in advance!
Update:
Thanks for the feedback. As a result I updated the following:
In my urls.py:
urlpatterns = [
url(r'^ajax/update_subcategories/$', views.update_subcategories, name='update_subcategories'),
And in my views.py:
def update_subcategories(request):
category = request.GET.get('category', None)
sub_category = list(SubCategory.objects.filter(category__name__exact=category).values('name'))
return JsonResponse(sub_category, safe=False)
And I have this in my myapp/search.html:
{% block javascript %}
<script>
$("#id_category").change(function () {
var category = $(this).val();
$.ajax({
url: '{% url "myapp:update_subcategories" %}',
data: {
'category': category,
},
success: function (response) {
var new_options = response;
alert(new_options[0].name); // works
$('#id_sub_category').empty();
$.each(new_options, function(key, value) {
$('#id_sub_category')
.append($('<option>', { value : key })
.text(value.name));
});
}
});
</script>
{% endblock %}
Update: The sub_category options were showing as [object Object] until I changed value to value.name and it looks like it's working. I'll test it out and close unless there are any comments.
Update: Im still having an issue with the browser back button. When a user clicks back the dropdown values have changed back to the original queryset rather than the updated version.
You can't do this from Django views side, ie, backend. You could try an ajax request for implementing this kind of requests, by sending a GET request to the server for populating the drop-down or whatever you are into.
For a simple example, you could refer
here
How do I POST with jQuery/Ajax in Django?
EDIT
def update_subcategories(request):
category = request.GET.get('category', None)
sub_category = list(SubCategory.objects.filter(category__name__exact=category).values('name'))
return JsonResponse(dict(sub_category=sub_category))
Then in ajax response you could grab it like response.data.sub_category
Use ajax to send the category and retrieve subcategory elements.
For the category, send it via get request, and using the orm return the subcategories in a json format which you can show using jQuery.

Django, jquery.formset and Select2 issues

Using Django 1.6, django-select2 (latest) and jquery.formset.js (latest), I'm struggling with something that should be quite simple. Essentially when I use the add formset capability provided by jquery.formset.js the new formset is missing the select field provided by django-select2, although the rest of the formset renders fine.
It's a fairly basic set up:
class PartNumber(models.Model):
name = models.CharField("Description", max_length=100)
supplier_part_number = models.CharField(max_length=30, unique=True, blank=True, null=True)
class PurchaseOrder(models.Model):
po_number = models.CharField('PO number', max_length=10, unique=True)
ordered_date = models.DateField(default=today)
class PurchaseOrderPart(models.Model):
part_number = models.ForeignKey(PartNumber, related_name='purchases')
po_number = models.ForeignKey(PurchaseOrder, related_name='partslist')
delivery_date = models.DateField(null=True, blank=True)
qty_ordered = models.IntegerField('Quantity ordered',validators=[MinValueValidator(1)])
cost = models.DecimalField('Unit Cost', max_digits=10,decimal_places=2,blank=True,null=True)
I have the create view of a PurchaseOrder having PurchaseOrderParts as an inline_formset:
class PurchaseOrderPartForm(forms.ModelForm):
part_numbers = PartNumberChoices()
class Meta:
fields = ('part_numbers', 'delivery_date', 'qty_ordered', 'cost')
model = PurchaseOrderPart
widgets={
'part_numbers': forms.Select(attrs={'class':'form-control'}),
'delivery_date': CalendarWidget(attrs={'class':'input-append form-control'}),
'qty_ordered': forms.NumberInput(attrs={'class':'form-control'}),
'cost': forms.NumberInput(attrs={'class':'form-control'}),
}
POPartFormset = inlineformset_factory(PurchaseOrder, PurchaseOrderPart, form=PurchaseOrderPartForm, extra=1, can_delete=True)
And I'm using jquery.formset.js so that there are "add" and "remove" buttons on the PurchaseOrder create view, so that any number of PurchaseOrderParts might be added (any one PO might have from 1 to infinite parts attached, in reality more likely to be < 10).
That was working fine.
But the PartNumber fk on a PurchaseOrderPart has a huge list (~2500 items) so the select list is inconvenient.
I installed django-select2 and was pretty impressed at how easily it was to get running:
class PurchaseOrderPartForm(forms.ModelForm):
part_numbers = PartNumberChoices()
class Meta:
fields = ('part_numbers', 'delivery_date', 'qty_ordered', 'cost')
model = PurchaseOrderPart
widgets={
'part_numbers': django_select2.AutoHeavySelect2Widget(),
'delivery_date': CalendarWidget(attrs={'class':'input-append form-control'}),
'qty_ordered': forms.NumberInput(attrs={'class':'form-control'}),
'cost': forms.NumberInput(attrs={'class':'form-control'}),
}
This is when we have problems. It all works until you use the jquery.formset.js to add a new formset - it renders perfectly but fails to include the django-select2 select.
In particular, the new formset is missing this code:
<div class="select2-container select2-container-active" id="s2id_id_partslist-1-part_numbers"> <span class="select2-chosen"> </span><abbr class="select2-search-choice-close"></abbr> <span class="select2-arrow"><b></b></span><input class="select2-focusser select2-offscreen" type="text" id="s2id_autogen5"></div>
How might I go about force inserting the select2-container?
This is a known bug of django-select2 that has been fixed in a very recent merge.
When you are saying that you are running the latest version, do you mean from github or from PIP ?
Either way, you might be interrested in this:
https://github.com/applegrew/django-select2/pull/127

Categories

Resources