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})
Related
After displaying my posts, I don't manage to Edit any of them.
When I print the instance variable which is in views.py in my terminal, it displays only the title and the author like this title - author, which is the method defined in models.py.
Help please!
Views.py
#login_required(login_url='login_view')
def update_post_view(request, post_id, slug=None):
instance = Article.objects.get(id = post_id)
if request.method == 'POST':
form = UpdatePostForm(request.POST, request.FILES, instance=instance)
if form.is_valid():
form.save()
return redirect('posts_view')
else:
form = UpdatePostForm(instance=instance)
return render(request,'update_post.html', {'form':form})
forms.py
class UpdatePostForm(forms.ModelForm):
class Meta:
model = Article
fields = ('author',)
title = forms.CharField(max_length=255, label='username',
widget= forms.TextInput(attrs= {'placeholder':'Title...', 'class': 'title'}))
body = forms.CharField(max_length=255, label='body', required=True, widget=forms.Textarea(attrs={'placeholder':'Start writing your post...'}))
urls.py
path('update_post/<int:post_id>/<slug:slug>', views.update_post_view, name='update_post_view')
update_post.html
{% extends 'base.html' %}
{% block title %}Update Post{% endblock %}
{% block content %}
<h2>Update Posts...</h2>
<form action="" method="POST">
{% csrf_token %}
<div>
<h3>{{form.title}}</h3>
<small>{{form.author}}</small>
<p>{{form.body}}</p>
</div>
<button class="btn btn-secondary">Update</button>
</form>
{% endblock %}
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.
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.
I've made some attempted to use formwizard but there wasn't much documentation about it so I decided to stay with the basic. I've successfully obtained and display the data from the first form to the second form and added some checkbox next to the data to allow user to choose whether to overwrite or ignore the duplicate data found in the backend process. The problem I have is the second form doesn't know how retrieve the data of the first form after hitting "Confirm" button. The form2.html template invalidated the data completely since it called itself again by the form action after submitting the data. Is there a way to solve this or a better approach to this?
forms.py
class NameForm (forms.Form):
first_name = forms.CharField (required = False)
last_name = forms.CharField (required = False)
class CheckBox (forms.Form):
overwrite = forms.BooleanField (required = False)
views.py
def form1 (request):
NameFormSet = formset_factory (NameForm, formset = BaseNodeFormSet, extra = 2, max_num = 5)
if request.method == 'POST':
name_formset = NameFormSet (request.POST, prefix = 'nameform')
if name_formset.is_valid ():
data = name_formset.cleaned_data
request.session ['data'] = data
context = {'data': data}
return render (request, 'nameform/form2.html', context)
else:
name_formset = NameFormSet (prefix = 'nameform')
context = {......}
return render (request, 'nameform/form1.html', context)
def form2 (request):
request.session ['data'] = data
CheckBoxFormSet = formset_factory (CheckBox, extra = 2, max_num = 5)
if request.method == 'POST':
checkbox_formset = CheckBoxFormSet (request.POST, prefix = 'checkbox')
if checkbox_formset.is_valid ():
data = checkbox_formset.cleaned_data
context = {'data': data}
return render (request, 'nameform/success.html', context)
else:
checkbox_formset = CheckBoxFormSet (prefix = 'checkbox')
return HttpResponse ('No overwrite data.')
form2.html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
{% load staticfiles %}
<link rel="stylesheet" type="text/css" href="{% static 'nodeform/style.css' %}" >
<title>User Information</title>
</head>
<body>
<h1>User Information:</h1>
<form action="form2" method="POST">
{{ checkbox_formset.management_form }}
<div id="tablefont">
<table id="table01">
<tr>
<th>First Name</th>
<th>Last Name</th>
<th class="center">Overwrite</th>
</tr>
{% for info in data %}
<tr>
<td>{{ info.first_name }}</td>
<td>{{ info.last_name }}</td>
<td class="center"><input id="id_checkbox-{{ forloop.counter0 }}-overwrite" name="checkbox-{{ forloop.counter0 }}-overwrite" type="checkbox" /></td>
</tr>
{% endfor %}
</table>
</div>
<br>
<p><input type="submit" value="Confirm">
<a href="{% url 'form1' %}">
<button type="button">Cancel</button></a></p>
</form>
</body>
</html>
Personally I find that class based views always make life simpler, and in this case specifically there is the Form Wizard views which use the session or a cookie. Check out the docs; https://django-formtools.readthedocs.io/en/latest/wizard.html
I've just finished writing something very similar to this;
from django.contrib.formtools.wizard.views import SessionWizardView
class SignupWizard(SessionWizardView):
template_name = 'wizard_form.html'
form_list = [Form1, Form2, Form3]
model = MyModel
def get_form_initial(self, step, **kwargs):
initial = self.initial_dict.get(step, {})
current_step = self.storage.current_step
if step or current_step in ['0', 0]:
initial.update({'field': 'data'})
elif step or current_step in ['1', 1]:
initial.update({'field': 'data'})
return initial
def get_context_data(self, form, **kwargs):
"""
Supply extra content data for each stage.
e.g. stage page title
"""
previous_data = None
if self.steps.current == self.steps.last:
previous_data = self.get_all_cleaned_data()
context = super(SignupWizard, self).get_context_data(form, **kwargs)
context.update(
{
'review_data': previous_data,
}
)
return context
def done(self, form_list, **kwargs):
"""
Final page, this is rendered after the post method to the final form.
"""
form_data_dict = self.get_all_cleaned_data()
mymodelform = form_list[0].save()
return HttpResponseRedirect()
Essentially there my first form is a ModelForm for MyModel and I use other standard forms to collect other information. So at the end, grab the first form from the list and save that to create the MyModel instance.
Equally as you can see you can grab self.get_all_cleaned_data() to get all of the data entered in to the forms through to whole process to handle the data yourself.
The template for something this would be along the lines of;
{% extends 'base_wizard.html' %}
{% load i18n %}
{% block form %}
{% for error in wizard.form.non_field_errors %}
{{ error }}
{% endfor %}
{{ wizard.form.media }}
{{ wizard.management_form }}
{% wizard.form.as_p %}
<div class="controls">
{% if wizard.steps.prev %}
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}">
{% trans "Previous step" %}
</button>
{% endif %}
<button type="submit" name="submit">
{% trans "Next step" %}
</button>
</div>
{% endblock form %}
I have 2 models, Father and Son.
I have a page to register Father. On the same page I have a formset to register Son.
On page has a button "more" to add another Father and their respective Son on the same page.
Does anyone have any examples using CreateView?
Class based views are still new, so I'll write this out. The process is simple:
First, create the forms for your objects. One of the forms will be repeated. Nothing special to be done here.
class SonInline(ModelForm):
model = Son
class FatherForm(ModelForm):
model = Father
Then, create your formset:
FatherInlineFormSet = inlineformset_factory(Father,
Son,
form=SonInline,
extra=1,
can_delete=False,
can_order=False
)
Now, to integrate it with your CreateView:
class CreateFatherView(CreateView):
template_name = 'father_create.html'
model = Father
form_class = FatherForm # the parent object's form
# On successful form submission
def get_success_url(self):
return reverse('father-created')
# Validate forms
def form_valid(self, form):
ctx = self.get_context_data()
inlines = ctx['inlines']
if inlines.is_valid() and form.is_valid():
self.object = form.save() # saves Father and Children
return redirect(self.get_success_url())
else:
return self.render_to_response(self.get_context_data(form=form))
def form_invalid(self, form):
return self.render_to_response(self.get_context_data(form=form))
# We populate the context with the forms. Here I'm sending
# the inline forms in `inlines`
def get_context_data(self, **kwargs):
ctx = super(CreateFatherView, self).get_context_data(**kwargs)
if self.request.POST:
ctx['form'] = FatherForm(self.request.POST)
ctx['inlines'] = FatherInlineFormSet(self.request.POST)
else:
ctx['form'] = Father()
ctx['inlines'] = FatherInlineFormSet()
return ctx
Finally, here is the template:
The key part is the jquery django-dynamic-formset plugin that keeps adding new inline forms:
<form id="father-form" method="POST" enctype="multipart/form-data" action=".">
{% csrf_token %}
<div class="row">
{% for f in form %}
<div class="span3">{{ f.label }}<br />{{ f }}
{% if f.errors %}
{% for v in f.errors %}
<br /><span style="color:red;">{{ v }}</span>
{% endfor %}
{% endif %}
</div>
{% endfor %}
</div>
<hr />
<h2>Sons:</h2>
<table class="table-striped">
<table>
{% for f2 in inlines %}
<tr id="{{ f2.prefix }}-row">
{% for i in f2 %}
<td>
{{ i }}{% if i.errors %}<span style="color:red;">{{ i.errors }}</span>{% endif %}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
{{ inlines.management_form }}
<input type="submit" class="btn btn-primary" value="Go Go Gadget →">
</form>
<script type="text/javascript">
$(function() {
$('#father-form tr').formset({
prefix: '{{ inlines.prefix }}'
});
})
</script>