Django saving string without unicode characters - python

I want to save my string in CharField and then display it as a value of input.
But when I save it, I got value in unicode characters. ex.
When I type "a" and I save it I got "(u'a',)"
and I want to get only "a"
In my html code I have form:
<form action="{% url 'edit'%}" method="post">
{% csrf_token %}
<input type="text" name="name" value="{{data.name}}" placeholder="{% trans 'Name' %}" required><br>
<button type="submit">{% trans 'Submit'%}</button>
</form>
My views:
#login_required
def edit(request):
user = MyUser.objects.get(pk=request.user.pk)
if request.method == "POST":
post = request.POST
editmodel = user.editmodel_set.all()[0]
editmodel.name = post.get('name')
shop.save()
And models:
class EditModel(model.Model):
name = models.CharField(max_length=100)
user = models.ForeignKey(settings.AUTH_USER_MODEL)

That is not a good way of working with forms. Do not use data in request.POST directly to save in the database.
For more information refer working with forms in django documentation.
Either create a model form or simple form, check posted data is valid and then save it in DB with appropriate data object.
If you still want to do that update your code as
editmodel.name = post.getlist('name')[0]

Related

How to loop through a form and add same form in django if we click add more button and store that in django

What I really want to do is , if a user click on "ADD more" button then a same form repeat itself and the values should store in database, if he/she doesn't click of that button then only the values from first form should be stored.
I am not able to get this, I just created a form , and a table in database for those details but can't loop though the form neither in data.
please help.
This is the form and the button:
This is the model.py code:
from django.db import models
class experience(models.Model):
company_name = models.CharField(max_length=100)
address = models.CharField(max_length=100)
startdate = models.Datefield(default = 01-01-2020)
lastdate = models.DateField(default = 01-01-2020)
profile = models.CharField(max_length=100)
description = models.TextField(max_length = 250)
This is the views.py code:
from django.shortcuts import render, redirect
import requests
from django.contrib.auth.models import User, auth
# Create your views here.
def profile(request):
return render(request, 'profile.html')
Unfortunately, there's no built-in way (as far as I know) in Django to do that without Javascript, but here's an approach:
HTML:
<div class="container" id="experiencesContainer">
<form method='POST' name='experienceForm'>
{{form.as_p}}
</form>
<form method='POST' name='experienceForm'>
{{form.as_p}}
</form>
<button type="button" id="addMoreButton">Add more</button>
<button type="submit">Save Changes</button>
</div>
Django POST method:
# Get a list of submitted forms
experiences = request.POST.getlist('experienceForm')
for experience in experiences:
# this is how you loop throuh every form
experience.get('company_name)
Your javascript something like:
// clonning his childs as well
let cloneForm = document.querySelector('form[name=experienceForm]').cloneNode(true);
document.querySelector('div#experiencesContainer').appendChild(cloneForm);
// see this https://www.w3schools.com/jsref/met_node_clonenode.asp
Of course this code is not tested but I've done this in several projects before, hope it works!
A simple way would be to request the same view from the "Add", just make sure your form view saves the data when request method is POST.
<form action="{% url 'your-form-url' %}" method="GET">
{% csrf_token %}
<input type="submit" value="Add">
</form>
one other way to repeat forms would be using formsets. Formsets allow you to repeat the same form 'extra' times. Check out the documentation for more about this.
def repeat_form(request):
ExpFormSet = formset_factory(ExperienceForm, extra=3)
#extra defines the no. of forms you want to display
if request.method == 'POST':
formset = ExpFormSet(request.POST, request.FILES)
if formset.is_valid():
# do something with the formset.cleaned_data
#loop through each form in the formser
for form in formset.cleaned_data:
obj = form.save()
else:
formset = ExpFormSet()
return render(request, 'exp_form.html', {'formset': formset})
The corresponding template should be:-
<form method="post">
{{ formset.management_form }}
{% for form in formset %}
{{ form.as_p }}
{% endfor %}
</form>
Make sure you add form.management_form. Using the combination of the above might solve your problem of taking and saving several inputs.

how to delete an object in django [duplicate]

i want to delete a task from the database so i use this code
this is my delete view
def task_Delete(request,id=None):
if request.method == 'POST':
form = TaskForm()
id = int(request.POST.get('task.id'))
task = Task.objects.get(id=id)
task.delete()
messages.success(request,"successfully delete")
return render_to_response('home.html', {'form': form})
and that is my urls.py
url(r'^task_Delete/$', views.task_Delete, name='task_Delete')
this the code of the button delete :
<form action="{% url 'task_Delete' %}" method="post" >
{% csrf_token %}
<input type="hidden" name="task_id" value="{{task.id}}" />
<input type="submit" value="delete task">
</form></td>
</tr>
when i click on delete nothing happend i don't know why , please help thanks in advance
There are various problems in your code (for example the TaskForm is not needed at all) however if you change the line
id = int(request.POST.get('task.id'))
to
id = int(request.POST.get('task_id'))
the object will probably be deleted; remember that the request parameter's name will be the same as the name of the input (task_id). I recommend using proper CBVs (a DeleteView) for what you want to do - if you want a slow and comprehensive tutorial on that I recommend this article: https://spapas.github.io/2018/03/19/comprehensive-django-cbv-guide/

Clean Django form fields with same name

I have a django template in which I'm dynamically rendering multiple fields (using ajax)
Below is a Django form (which has been rendered in a template) whose fields have same names. I want to use the cleaned_data method to clean form data in views.py before storing them in the database.
index.html
<div class="form-container">
<!-- ASSUMING I HAVE ALREADY ADDED FIELDS DYNAMICALLY -->
<form id = "orderForm" action="newPickupOrder/" method="post" name="processForm">
<input type='text' name='this_field'>
<input type='text' name='this_field'>
<button type="submit">Submit</button>
</form>
</div>
<form id="addItemForm">
{% csrf_token %}
<!-- BUTTON TO ADD MORE FIELDS DYNAMICALLY -->
<button id = "addItemButton">Add item</button>
</form>
<script>
var addItemButton = document.querySelector('#addItemButton');
addItemButton.onclick = function(){
$.ajax({
type: 'POST',
url: 'addItem/',
data: addItemForm.serialize(),
success: function (response) {
$("#orderForm").append(response);
console.log('Success');
},
error: function (response) {
console.log('Error = '+response);
}
});
};
</script>
forms.py
class ItemForm(forms.Form):
this_field = forms.CharField()
urls.py
urlpatterns = [
url(r'^newPickupOrder/$', views.pickup_order_view, name='new_pickup_order'),
]
views.py
def add_item(request):
if request.method == 'POST':
itemForm = ItemForm()
return HttpResponse(itemForm.as_p())
def pickup_order_view(request):
if request.method == 'POST':
form = ItemForm(request.POST)
same_name_fields = request.POST.getlist('this_field')
# WANT TO CLEAN DATA IN same_name_fields
if form.is_valid():
print(form.cleaned_data)
# ONLY PRINTS THE LAST FIELD's DATA
return HttpResponseRedirect('/viewPickupRequests')
The problem I'm facing is that if I use form.cleaned_data['this_field'], only the last field's data is fetched i.e. in this example, the field with value anotherTestValue is fetched and cleaned. If I fetch the data using request.POST.getlist('this_field'), all the fields' data is fetched and stored as a list, but, I don't know how to clean it using cleaned_data method. Is there a way to apply the cleaned_data method to the list of field data?
I'm sorry, I can't test if this works so this is not really an answer - but the comment system is not suitable for larger code chunks so I'm posting here.
Django forms lack a field type that renders to multiple text inputs with the same name. The proper thing to do would be to write a new form field class and a new widget. Since you are not rendering the form in the template (you are using it only for validation) I will omit the widget part.
class AcceptAnythingMultipleChoiceField(forms.MultipleChoiceField):
def validate(self, value):
if self.required and not value:
raise ValidationError(
self.error_messages['required'],
code='required'
)
Then use this field class instead of forms.CharField() (you may need to pass an empty choices parameter).
[update]
So essentially what you're saying is that I need to create new form field class and then render it to the template each time the user wants to add a new field? What if user has to add 15 fields, I'll need to create 15 classes then! I think this method won't be suitable in scenarios where number of fields required to be generated is large. I feel there should be some elegant way to do this which i'm not aware of – The OP
No, it is not what I'm saying. You probably want to subclass something like MultipleHiddenInput and set AcceptAnythingMultipleChoiceField.widget to it. You will have to create a new template based on the template for MultipleHiddenInput and replace input type="hidden" for type="text" (the original template is django/forms/widgets/multiple_hidden.html).
class AcceptAnythingWidget(MultipleHiddenInput):
template_name = 'django/forms/widgets/multiple_visible.html'
class AcceptAnythingMultipleChoiceField(forms.MultipleChoiceField):
widget = AcceptAnythingWidget
def validate(self, value):
if self.required and not value:
raise ValidationError(
self.error_messages['required'],
code='required'
)
This should render as many <input name='this_field'> as needed for instantiated forms at the frontend if you use:
{{ form.this_field }}
in the template, but will not add/remove them dynamically.
In order to do that you must plug in the JavaScript required to add/remove inputs dynamically in the widget but I will left this as an exercise for you. Look at Form Assets (the Media class) in the docs in order to figure out how to do that.
I think that what you are looking for is formsets. https://docs.djangoproject.com/en/2.0/topics/forms/formsets/
from django.forms import formset_factory
ItemFormSet = formset_factory(ItemForm, extra=2)
You can the essentialy use ItemFormSet in the way you would use a normal form except that this objects is iterable.
You will also have to change your jquery if you want to dynamically add items. There are many examples online on how to do this. In short what you do is
clone one of the forms in the formset
clear all the values from the copied form
update the input's (prefixes of) id's
Using Formsets doesn't solve the problem of fetching and validating
fields with same name. The issue still remains
It does however generate the end result you wanted (see below). My question would be why you need to have inputs with the same name? If there is some jquery stuff that uses these names I dont see any reason why you wouldn't be able to use name like... or assign a class to the inputs instead.
def pickup_order_view(request):
if request.method == 'GET':
ItemFormSet = formset_factory(ItemForm, extra=5)
item_formset = ItemFormSet()
template = "some_template.html"
template_context = {'item_formset': item_formset}
return render(request, template, template_context)
if request.method == 'POST':
ItemFormSet = formset_factory(ItemForm)
item_formset = ItemFormSet(request.POST)
same_name_fields=[]
if item_formset.is_valid():
for item_form in item_formset:
same_name_fields.append(item_form.cleaned_data['this_field'])
print(same_name_fields)
Template
<form id = "orderForm" action="newPickupOrder/" method="post" name="processForm">
{% csrf_token %}
{{ item_formset.management_form }}
{{ for item_form in item_formset }}
{{ item_form.as_p }}
{{ endfor }}
<input type='submit' value='submit'>
</form>
Go to newPickupOrder/ , fill in the 5 fields, hit submit, and watch it print your list.

How can I edit an object without saved it in Django

There is a problem with my Django project, when I add an object it saves immediatly after that I will be redirected by object id to server_edit where I can fill fields. If I fill no fields and push "back" (go to previous page) browser button object will be saved without any data even if Save button was not pushed on template.
Is there any way do not save object where no fields was filled?
How can I edit an object without saved it?
I have a model "Server" that contains a few CharField
class Server(models.Model):
name = models.CharField(max_length=256)
I add and save an object:
def server_add(request):
server = Server()
server.save()
return HttpResponseRedirect(reverse('server:server_edit', args=(server.id,)))
after this I redirect to edit page:
def server_edit(request, server_id):
server = get_object_or_404(Server, pk=server_id)
return render(request, 'server/server_edit.html'{'server': server})
Fields will be edited on html template:
<form action="{% url 'server:server_edit_post' server.id %}" method="post">
{% csrf_token %}
<tr>
<td>{% trans "Name:" %}</td>
<td><input type="text" name="name" maxlength="256" value="{{server.name}}" required></td>
</tr>
<button type="submit" class="btn btn-success">{% trans "Save" %}</button>
</form>
This view gets data from the template and allows to edit them:
def server_edit_post(request, server_id):
server= get_object_or_404(Server, pk=server_id)
name = request.POST['name']
server.name = name
server.save()
return HttpResponseRedirect(reverse('server:server_index', args=()))
You should avoid saving object and then filling it with data in different view.
Try using generic edit views such as CreateView/EditView or FormView with Django forms (https://docs.djangoproject.com/en/1.9/ref/class-based-views/generic-editing/).
Example:
class ServerCreateView(CreateView):
form_class = ServerCreateForm
template_name = 'servers/add.html'
With this, all validation is done automatically.
Http calls should be stateless. The connection can be dropped any time, which leaves the DB in the same inconsistent state which is what you try to avoid here. Instead of using the form which only contains name, you could just redirect the user to a new page with the form for the rest of the data with the previously entered name as a get parameter, and pre-fill that form with the name on that page

Unable to pass multiple POST parameters from Django template

I'm passing POST parameters via a Django template. The template is basic:
<form method="POST" action="{% url 'registration_id' %}">
{% csrf_token %}
<input name="registration_id" value="{{ registration_id }}">
<input name="device_id" value="{{ device_id }}">
<button>Submit</button>
</form>
In the model, registration_id is a required TextField, whereas device_id is an optional hex field. To test my set up, I use a Mozilla add-on called HttpRequester. It works perfectly if:
1- I POST content to my URL like so:
csrfmiddlewaretoken=foobar&registration_id=foo
2- or like so:
csrfmiddlewaretoken=foobar&registration_id=foo&device_id=
(i.e. pass nothing in device_id, but mention the variable)
3- But nothing gets POSTed if I do:
csrfmiddlewaretoken=foobar&registration_id=foo&device_id=1234abcd
(ensuring device_id is a hex value)
Views.py is:
class DeviceCreateView(FormView):
model = GCMDevice
form_class = DeviceForm
template_name = "deviceobj_form.html"
def form_valid(self, form):
reg_id = self.request.POST.get('registration_id','')
dev_id = self.request.POST.get('device_id','')
if is_hex(dev_id):
GCMDevice.objects.create(registration_id=reg_id, device_id=dev_id)
else:
GCMDevice.objects.create(registration_id=reg_id, device_id='abcdef2222')
return render_to_response('success.html',RequestContext(self.request,{}))
def is_hex(s):
try:
int(s,16)
return True
except ValueError:
return False
What am I doing wrong in 3rd choice?
Was an error in the push-notifications library I was using, not in my code posted above. With either postgres or mysql as the database engine, attempting to create or update a gcm device using a form and http post was failing. The validators were being run against a string value, thus min and max validation were failing. Rewrote the validators to run against an integer value.

Categories