Autocomplete does nothing. What is wrong? - python

I have autocomplete code which does not work.
I have input field class Coordinate where when i type code it finds value from my DB that matches with geo_code and hence finds the input code country.
So when i type UK it matches with geo_code and then matches the last with the country so in this case UK is code i type it can be found in geo_code and country is United Kingdom. The code works, what i want to achieve is bring autocomplete to give suggestions while typing. for examples:
UK United Kingdom
USA United States of America
What i did so far:
In models.py i have:
class Coordinate(models.Model):
code = models.CharField(max_length=150)
class Profiles(models.Model):
geocode=models.CharField(max_length=200)
country=models.CharField(max_length=500)
city=models.CharField(max_length=500)
class Meta:
managed=False
db_table='profiles_country'
def __str__(self):
return '{}'.format(self.geocode)
in forms.py:
from dal import autocomplete
class CoordinateForm(forms.ModelForm):
code= forms.CharField(max_length=150, label='',widget= forms.TextInput)
class Meta:
model = Coordinate
fields = ('__all__')
widgets = {
'code': autocomplete.ModelSelect2(url='coordinate-autocomplete')}
in views.py:
class CoordinateAutocomplete(autocomplete.Select2QuerySetView):
def get_queryset(self):
if not self.request.user.is_authenticated():
return Profiles.objects.none()
qs = Profiles.objects.all()
if self.q:
qs = qs.filter(name__istartswith=self.q)
return qs
in base.html
<!DOCTYPE html>
{% load static %}
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="{% static 'geoproj/css/main.css' %}">
</head>
<body>
<div>{% block content %}{% endblock %}
{% block javascripts %} {% endblock %} </div>
</body>
</html>
in geo.html :
{% extends "base.html" %}
{% block content %}
{% if user.is_authenticated %}
<form enctype="multipart/form-data" method="POST" >
{% csrf_token %}
{{ form}}
{{form.media }}
<button class = "btn btn-primary" type="submit">OK</button></form>
{% endif %}
{% endblock content %}
{% block javascripts %} {% endblock %}
I would appreciate you help to solve this case.

models.py:
class Coordinate(models.Model):
code = models.CharField(max_length=150)
def __str__(self):
return self.code
class Profiles(models.Model):
geocode=models.CharField(max_length=200)
country=models.CharField(max_length=500)
city=models.CharField(max_length=500)
class Meta:
managed=False
db_table='profiles_country'
def __str__(self):
return '{}'.format(self.geocode)
views.py:
def geoview(request):
if request.method == "POST":
#do your operations
return render(request, 'result.html')
return render(request, 'index.html')
def getgeocode(request, geocode):
results = Coordinate.objects.filter(code__istartswith=str(geocode))
sendres = ""
for resn in results[:10]:
sendres += "<option class='bg-primary'>" + resn.code + "</option>"
return HttpResponse(sendres)
index.html:
{% extends 'base.html' %}
{% block content %}
<form enctype="multipart/form-data" method="POST">
<input type="text" list="mylist" name="geocodes" id="geocodes" placeholder="enter geocde"
onkeyup="getGeoCode(this.value)" autocomplete="off"/>
<datalist id="mylist">
</datalist>
<button class="btn btn-primary" type="submit">OK</button>
</form>
{% endblock content %}
{% block javascripts %}
<script>
function getGeoCode(str) {
if (str.length == 0) {
document.getElementById("mylist").innerHTML = "";
document.getElementById("mylist").style.border = "0px";
return;
}
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
} else {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("mylist").innerHTML = this.responseText;
}
}
xmlhttp.open("GET", "/coordinate-autocomplete/" + str, true);
xmlhttp.send();
}
</script>
{% endblock javascripts %}
urls.py:
from django.urls import path
from app import views
urlpatterns = [
....
path('geo/', views.geoview, name='geo'),
path('coordinate-autocomplete/<geocode>', views.getgeocode, name='coordinate-autocomplete'),
....
]
and you can confirm its working in your terminal you will see get request like:
/coordinate-autocomplete/{word_in_iput}
[17/Apr/2020 16:19:52] "GET /coordinate-autocomplete/u HTTP/1.1" 200 120
[17/Apr/2020 16:20:03] "GET /coordinate-autocomplete/us HTTP/1.1" 200 65
[17/Apr/2020 16:20:06] "GET /coordinate-autocomplete/u HTTP/1.1" 200 120
[17/Apr/2020 16:20:13] "GET /coordinate-autocomplete/i HTTP/1.1" 200 44

I don't see the js that links the URL response and HTML template. Here how I will solve it. Provided your view works.
You will generate the suggestion by
First Creating a js event listener to get text from the input box of the
form
Once you get this text you will do an ajax call to the view URL
you have mention
After you get ajax result you will then create a for
loop and generate select tags for the input.
This is how I would write the js code to communicate with the Html template and Django autocomplete view URL.

code field in the CoordinateForm is CharField, not ModelChoiceField, so it fails to work correctly with QuerySet returned by autocomplete.

Related

Django Update Database record is not working

Iam trying to get a records which works, but it just does not want to update the record...
----forms.py----
class acroniform(forms.ModelForm):
def clean_key(self):
Key = self.cleaned_data['Key']
if Acronis.objects.filter(id_iexact=Key).exists():
raise forms.ValidationError('Dieser Key ist bereits vergeben')
return Key
class Meta:
model = Acronis
fields = ('KN', 'Key', 'Release')
labels = {
'KN': 'Kundennummer',
'Key': 'Key',
'Release': 'Release',
}
----urls.py----
from django.urls import path
from . import views
app_name = 'blog'
urlpatterns = [
path('EditAcronis/<int:id>', views.edit_acronis, name='edit_acronis'),
]
----Views.py----
#login_required()
def edit_acronis(request, id=None):
item = get_object_or_404(Acronis, id=id)
acroniform_form = acroniform(request.POST or None, instance=item)
if acroniform_form.is_valid():
item = acroniform_form.save(commit=False)
item.save(force_update=True)
return redirect('/Verwaltung/Acronis')
else:
form = acroniform(instance=item)
return render(request, 'blog/editacronis.html', {'acroniform_form': acroniform_form})
----editacronis.html----
{% extends 'blog/base.html' %}
{% load bootstrap4 %}
<html lang="en">
<meta charset="UTF-8">
<title>{% block supertitle %} Home {% endblock %}</title>
{% block Content %}
<P></P>
<form class="form-inline, form-row" action="{% url 'blog:acr' %}" method="post">
{% csrf_token %}
{% bootstrap_form acroniform_form %}
<button type="submit" class="btn btn-success">Update</button>
</form>
<p>Acronis</p>
<P></P>
{% endblock %}
What's wrong with my code?
item.save() is not saving or updating the databaserecord...
{% extends 'blog/base.html' %}
{% load bootstrap4 %}
<html lang="en">
<meta charset="UTF-8">
<title>{% block supertitle %} Home {% endblock %}</title>
{% block Content %}
<P></P>
<form class="form-inline, form-row" action="" method="post">
{% csrf_token %}
{% bootstrap_form acroniform_form %}
<button type="submit" class="btn btn-success">Update</button>
</form>
<p>Acronis</p>
<P></P>
{% endblock %}
Try this.
class acroniform(forms.ModelForm):
def clean_key(self):
Key = self.cleaned_data['Key']
if Acronis.objects.filter(key_iexact=Key).exists():
raise forms.ValidationError('Dieser Key ist bereits vergeben')
return Key
class Meta:
model = Acronis
fields = ('KN', 'Key', 'Release')
labels = {
'KN': 'Kundennummer',
'Key': 'Key',
'Release': 'Release',
}
#login_required()
def edit_acronis(request, id):
item = get_object_or_404(Acronis, id=id)
form = acroniform(request.POST or None, instance=item)
if form.is_valid():
form.save()
return redirect('/Verwaltung/Acronis')
else:
form = acroniform(instance=item)
return render(request, 'blog/editacronis.html', {'acroniform_form': acroniform_form})
or
#login_required()
def edit_acronis(request, id):
item = get_object_or_404(Acronis, id=id)
form = acroniform(request.POST, instance=item)
if form.is_valid():
form = acroniform.save(commit=True)
form.save()
return redirect('/Verwaltung/Acronis')
else:
form = acroniform(instance=item)
return render(request, 'blog/editacronis.html', {'acroniform_form': acroniform_form})

request.session isn't saved or is somehow modified

It seems that my request.session isn't saved or is somehow modified in other ways, despite using request.session.modified = True after changing the value.
Here is the debug output:
This should run first.
This should run second.
I have set main category to 2 (Shoes)
Main category is 1 (Books)
The code below should display a different ModelForm based on selected category, however when I select, for instance, Books, ShoesModelForm is displayed and vice-versa. This currently works as follows: whenever a value in a combobox is changed, two AJAX requests are fired. First one calls a view (load_categories) that renders another if a category has children, otherwise returns an HttpResponse which stops attaching the listener. Second one calls a view (load_modelform) that renders a specific ModelForm if selected category is root node (main category).
mappings = {
'1': BookProductForm,
'2': ShoesProductForm
}
def load_categories(request):
print("This should run first.")
category_id = request.GET.get('category')
request.session['category'] = category_id
request.session.modified = True
if Category.objects.get(id=category_id).is_root_node():
request.session['main_category'] = category_id
request.session.modified = True
print(f"I have set main category to {request.session['main_category']} ({Category.objects.get(id=category_id).name})")
subcategories = Category.objects.get(id=category_id).get_children()
if subcategories:
return render(request, 'products/category_dropdown_list_options.html', {'subcategories': subcategories})
return HttpResponse('leaf_node')
def load_modelform(request):
print("This should run second.")
main_category = request.session['main_category']
print(f"Main category is {main_category} ({Category.objects.get(id=main_category).name})")
form = mappings[main_category]
return render(request, 'products/category_modelform.html', {'form': form})
#login_required
def product_create_view(request):
if request.method == 'POST':
category = request.session.get('main_category')
create_product_form = mappings[category](request.POST)
if create_product_form.is_valid():
create_product_form.save()
return render(request, 'products/product_create.html', {
'categories': Category.objects.filter(parent=None)
})
What might be going on here?
#EDIT:
I'm including my template with jQuery code that contains Ajax requests:
{% extends 'pages/base.html' %}
{% load static %}
{% block cssfiles %}
<link rel="stylesheet" type="text/css" href="{% static 'products/css/create.css' %}">
{% endblock %}
{% block content %}
<h1>Create a product</h1>
<div class='modelform'>
<form method='POST' id='productForm' data-products-url="{% url 'products:ajax_load_categories' %}" data-modelform-url="{% url 'products:ajax_load_modelform' %}">
{% csrf_token %}
<div class='categories'>
<label>Category</label>
<select>
{% for category in categories %}
<option value="{{ category.pk }}">{{ category.name }}</option>
{% endfor %}
</select>
</div>
<div class='the-rest'>
{{ form.non_field_errors }}
{% for field in form %}
{% ifnotequal field.name 'category' %}
{{ field.label_tag }} {{ field }}
{{ field.errors }}
{% endifnotequal %}
{% endfor %}
</div>
<input type="submit" name="" value="Submit">
</form>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>
var $r_ = function() {
var url = $("#productForm").attr("data-products-url");
var categoryId = $(this).val();
var toRemove = $(this).nextAll('select');
$.ajax({
url: url,
data: {
'category': categoryId
},
success: function (data) {
if (data != 'leaf_node') {
toRemove.remove();
$(".categories").append(data);
}
else {
toRemove.remove();
}
}
});
var url2 = $('#productForm').attr('data-modelform-url');
setTimeout(function() {
$.ajax({
url: url2,
data: {
'category': categoryId
},
success: function (data) {
if (data != 'dont_change_modelform') {
$('.the-rest').empty();
$('.the-rest').append(data);
}
}
});
}, 100);
}
$(document).on('change', 'select', $r_);
</script>
{% endblock %}

child node is treated as grand child node when trying to structure

I am using django-mptt library for the category. I could show the list of categories in template but I wanted to indent it properly so user can know which is a main category and which one is sub-category and etc. The way i tried to structure is
{% recursetree nodes %}
<li class="node">
<a href="/category/{{ node.get_absolute_url }}"
class="{% if not node.is_leaf_node and not node.is_root_node and node.is_child_node %} child_parent {% elif node.is_leaf_node and not node.is_root_node %}leaf_node{% endif %}">
{{ node.name }}
{% if node.is_root_node %}
<span class="badge">{{ node.get_count_children }}</span>
{% endif %}
</a>
{% if not node.is_leaf_node %}
<ul class="children">
<li>{{ children }}</li>
</ul>
{% endif %}
</li>
{% endrecursetree %}
This yields the following design of category
Here Dressing Table is a child of Bedroom Items like Bed and Almirah not a child of Bed. How could i fix this? I know the problem is here
<a href="/category/{{ node.get_absolute_url }}"
class="{% if not node.is_leaf_node and not node.is_root_node and node.is_child_node %} child_parent {% elif node.is_leaf_node and not node.is_root_node %}leaf_node{% endif %}">
but could not fix this issue
Not the dressing table in the screenshot
According to you updated answer.
Dinning Set, Kitchen Rack, and Kitchen Setup(Modular Kitchen) are supposed to be cyan since they are second level.
If my understanding is correct.
Here is my hacked solution. If anybody found the better one please raise.
Add extra method to the Model instance
I have to add nodes to the context. (This would be an optional if you are using Django2.0 like mine)
Use the instance method in the template
models.py
from django.db import models
from mptt.models import MPTTModel, TreeForeignKey
class Genre(MPTTModel):
name = models.CharField(max_length=50, unique=True)
parent = TreeForeignKey('self', null=True, blank=True, related_name='children', db_index=True,
on_delete=models.CASCADE)
class MPTTMeta:
order_insertion_by = ['name']
def __str__(self):
return f'{self.name}'
def is_second_node(self):
return True if (self.get_ancestors().count() == 1) else False
views.py
from django.views.generic import ListView
from genres.models import Genre
class GenreListView(ListView):
model = Genre
template_name = 'genre_list.html'
def get_context_data(self, *, object_list=None, **kwargs):
"""Get the context for this view."""
queryset = object_list if object_list is not None else self.object_list
page_size = self.get_paginate_by(queryset)
context_object_name = self.get_context_object_name(queryset)
if page_size:
paginator, page, queryset, is_paginated = self.paginate_queryset(queryset, page_size)
context = {
'paginator': paginator,
'page_obj': page,
'is_paginated': is_paginated,
'object_list': queryset
}
else:
context = {
'paginator': None,
'page_obj': None,
'is_paginated': False,
'object_list': queryset
}
if context_object_name is not None:
context[context_object_name] = queryset
context.update(kwargs)
context['nodes'] = context.get('object_list')
return super().get_context_data(**context)
genre_list.html
<!DOCTYPE html>
{% load mptt_tags %}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Genre ListView</title>
</head>
<style>
.root {color: purple}
.child{color: cyan}
.leaf {color: gray}
</style>
<body>
{% recursetree nodes %}
<div class="
{% if node.is_root_node %}
root
{% elif node.is_child_node and not node.is_leaf_node or node.is_second_node%}
child
{% elif node.is_leaf_node and not node.is_root_node%}
leaf
{%endif%}">
{{node.name}}
{{node.is_second_node}}
</div>
{% if not node.is_leaf_node%}
<ul>{{children}}</ul>
{% endif %}
{% endrecursetree %}
</ul>
</body>
</html>

post_detail() view missing required positional arguments:

I'm beginner to django . I am facing this problem that I can't get the post detail view with year , month and post .
Error is post_detail() missing 4 required positional arguments: 'year', 'month', 'day', and 'post'.
this is models.py
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
class Post(models.Model):
STAUTS_CHOICE = ( ('draft','Draft'),('published','Published'),)
title =models.CharField(max_length =250)
slug = models.SlugField(max_length =250)
author = models.ForeignKey(User,related_name='blog_post')
body = models.TextField()
publish =models.DateTimeField(default = timezone.now)
created = models.DateTimeField(auto_now_add=True)
udated = models.DateTimeField(auto_now=True)
status = models.CharField(max_length =250 ,
choices = STAUTS_CHOICE , default = 'draft')
class Meta:
ordering = ('-publish',)
def get_absolute_url(self):
return reverse('blog:post_detail', args = [self.slug, self.publish.year , self.publish.strftime('%m'), self.publish.strftime('%d')]])
def __str__(self):
return self.title
______________________________________________________________
this is views.py
from django.shortcuts import render , get_object_or_404
from .models import Post
def post_list(request):
post = Post.objects.all()
return render(request,'blog/post/list.html',{'post':post})
def post_detail(request,slug,year, month,day,post):
post = get_object_or_404(Post, slug = slug , status = 'published' ,publish_year = year, publish_month = month , publish_day = day)
return render(request,'blog/post/detail.html',{'post':post})
this is urls.py
from django.conf.urls import url
from .import views
urlpatterns = [
url(r'^post_list',views.post_list,name ='post_list'),
url(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/'r'(?P<slug>[-\w]+)/$',views.post_detail,name='post_detail'),
this is post_detail.html page
{% extends 'blog/base.html' %}
{% block title %}Post details{% endblock %}
{% block content %}
<h2><a>{{post.title}}</a></h2>
<p class="date">published {{ post.published}} by {{ post.author}}</p>
{{ post.body|linebreaks }}
{% endblock %}
this is list.html page :
{% extends 'blog/base.html' %} {% block head_title %}Posts list{% endblock %}
{% block content %}
<h1>My Blog</h1>
{% for x in posts %}
<h2>
{{x.title}}
</h2>
<p class="date">published {{ x.published}} by {{ x.author}}</p>
{{ x.body|truncatewords:30|linebreaks }} {% endfor %} {% endblock %}
this is base.html
{% load staticfiles %}
<!DOCTYPE html>
<head>
<title>{% block head_title %}Welcome to my blog{% endblock %}</title>
<!-- <link rel="stylesheet" href=""> -->
</head>
<body>
<div id="sidebar">
<h1></h1>
</div>
<div id="content">
{% block content %} {% endblock %}</div>
</body>
</html>
So far I guessed you want to resolve domain/year/month/day/slug URL.
The following changes will make it work.
views.py
def post_detail(request,slug,year, month,day):
post = get_object_or_404(Post, slug = slug , status = 'published' ,publish__year = year, publish__month = month , publish__day = day)
return render(request,'blog/post/detail.html',{'post':post})
urls.py
urlpatterns = [
url(r'^post_list',views.post_list,name ='post_list'),
url(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/(?P<slug>[-\w]+)/$',views.post_detail,name='post_detail'),
]
remove post parameter from post_detail view. and remove third url for same view. Now your requested url should be:
localhost:8000/2017/12/16/my-post

My django form fields are not showing up in template

forms.py
class ImageCreateForm(forms.ModelForm):
class Meta:
model = Image
fields = {'title', 'url', 'description'}
widgets = {
'url':forms.HiddenInput,
}
def clean_url(self):
url = self.cleaned_data['url']
valid_extensions = ['jpg', 'jpeg']
#The two below codes do exactly the same thing but partition is faster
extention = url.rpartition('.')[2].lower()
#extension = url.rsplit('.',1)[1].lower()
if extension not in valid_extensions:
raise forms.ValidationError('The given URL does not match valid image extensions')
return url
def save(self, force_insert=False,force_update=False,commit=True):
image = super(ImageCreateForm, self).save(commit=False)
image_url = self.cleaned_data['url']
image_name = '{}.{}'.format(slugify(image.title), image_url.rpartition('.')[2].lower())
#download image from the given URL
response = request.urlopen(image_url)
image.image.save(image_name,ContentFile(response.read()),save=False)
if commit:
image.save()
return image
The image appears alright but the fields are not showing
index.html
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block title %}Bookmark an image{% endblock %}
{% block content %}
<h1>Bookmark an image</h1>
<img src="{{ request.GET.url }}" class="image-preview">
<form action="." method="post">
{{ forms.as_p }}
{% csrf_token %}
<input type="submit" value= 'Bookmark it!'>
</form>
{% endblock %}
change your form to this
you pass the fields in list and not set type {}
class ImageCreateForm(forms.ModelForm):
class Meta:
model = Image
fields = ['title', 'url', 'description']
widgets = {
'url':forms.HiddenInput,
}
in your views
def image_create(request):
if request.method == 'POST':
#form is sent
form = ImageCreateForm(request.POST)
if form.is_valid():
#form data is valid
cd = form.cleaned_data
new_item = form.save(commit=False)
#assign current user to the item
new_item.user = request.user
new_item.save()
messages.success(request, 'Image added successfully')
#redirect to new created item detail view
return redirect(new_item.get_absolut_url())
else:
#build form with data provided by the bookmarklet via GET
form = ImageCreateForm()
return render(request, 'images/image/index.html',{'section':'images', 'form':form})
and in html
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block title %}Bookmark an image{% endblock %}
{% block content %}
<h1>Bookmark an image</h1>
<img src="{{ request.GET.url }}" class="image-preview">
<form action="." method="post">
{{ form.as_p }}
{% csrf_token %}
<input type="submit" value= 'Bookmark it!'>
</form>
{% endblock %}
Although it does not look like it, make sure that the if request.method and its related else are on the same level. I sometimes get the else indented to match the if form.is_valid level.

Categories