I was updating the data in the database by takin the data from an html form when this appeared. I have faced this problem earlier also but I dont remember how to solve it .
my views.py part
def update(request,pk):
task = Task.objects.get(id=pk)
context = {
'task':task,
}
if request.method=="POST":
task.title= request.POST.get('taskname' )
task.save()
return redirect('/main')
return render(request,"update.html",context)
models.py file :
class Task(models.Model):
title = models.CharField(max_length =200)
complete = models.BooleanField(default = False , blank=True)
created = models.DateTimeField(auto_now=True)
my html file :
<div class="container">
<div class="jumbotron mt-3">
<form method= "post">
{% csrf_token %}
<h1 class="text-center">{{task}}</h1>
<input type="text" class="form-control rounded " id="task_name" name="task_name"
aria-describedby="emailHelp" placeholder="Add the task !">
<p class="lead text-center" > Do you really want to update ?</p>
<button class="btn btn-lg btn-primary" type ="submit" >Update »</button>
</form>
</div>
</div>
Your html input element's name attribute does not match the key you are attempting to access in request.POST. You would need to update your name attribute on your input to name="taskname" as opposed to name="task_name"
I would also suggest taking a look at Django's form docs and possibly adding validation since your error was caused by attempting to update the Task.title field with a None value
Related
I am currently working on my maiden django project where an authorised person can save their daily expenses. I have created the login and signup page using UserCeationForm and AuthenticationForm. My code for the same is:
def login_view(request):
if request.method == 'POST':
form= AuthenticationForm(data=request.POST)
if form.is_valid():
user=form.get_user()
login(request,user)
return render (request, 'tasks_notes/index.html')
else:
form= AuthenticationForm()
return render(request, 'registeration/login.html', {'form':form})
def signup_view(request):
if request.method == 'POST':
form= UserCreationForm(request.POST)
if form.is_valid():
user=form.save()
login(request,user)
return redirect('login')
else:
form=UserCreationForm()
return render(request, 'tasks_notes/signup.html',{'form':form})
I have created a page named index.html where I am giving input to save my daily expenses wfor the appropriate (logged in) user as:
<form class="col s12" action='{% url "add item" %}' method='post'>
{% csrf_token %}
<div class="row">
<div class="container center">
<h3 class='center'>Your total budget is: <span style="color:green;">{{ budget }}</span> dollars</h3>
<h3 class='center'>You've spent a total of: <span style="color:red;">{{ expenses }}</span> dollars</h3>
<br>
<br>
<div class="input-field col s3">
<input placeholder="Expense name" name="expense_name" id='expense_name' type='text' class='validate'>
<label for='expense_name'>Expense name</label>
</div>
<div class="input-field col s3">
<input placeholder='Amount' name='cost' id='cost' type='text' class='validate'>
<label for='cost'>Amount</label>
</div>
<div class="input-field col s3">
<input placeholder='Date of Expense' name="expense_date" id="expense_date" type="text" class='datepicker'>
<label for="expense_date">Expense Date</label>
</div>
<button class="btn waves-effect waves-light" type="submit" name="action">Add Expense
<i class="material-icons right">add_circle</i>
</button>
</div>
</div>
</form>
I am trying to take the inputs and put that in views.py file as:
def additem_view(request):
name = request.POST['expense_name']
expense_cost = request.POST['cost']
expense_date = request.POST['expense_date']
create=BudgetInfo.objects.create(items=name,cost=expense_cost,date_added=expense_date)
create.save()
return HttpResponseRedirect('app')
My models.py file is:
from django.db import models
from django.contrib.auth.models import User
class BudgetInfo(models.Model):
items= models.CharField(max_length=20)
cost= models.FloatField(blank=False, null=True)
date_added= models.DateField(auto_now=True)
user= models.ForeignKey(User, on_delete= models.CASCADE)
When I am giving the input in my web page, I am getting an error like this:
Exception Type: IntegrityError
Exception Value: NOT NULL constraint failed: tasks_notes_budgetinfo.user_id
I have checked for budgetinfo.user_id in my dbsqlite database I found this:
CREATE TABLE IF NOT EXISTS "tasks_notes_budgetinfo" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "items" varchar(20) NOT NULL, "cost" real NULL, "date_added" date NOT NULL, "user_id" integer NOT NULL REFERENCES "auth_user" ("id") DEFERRABLE INITIALLY DEFERRED);
Sorry for such long explanation of my question. Can anyone tell me where am I wrong? It will be a great help.
Thank you.
try this
<form class="col s12" action='{% url "add item" %}' method='post'>
{% csrf_token %}
<input type="text" name="id" value="{{user.id}}">
</form>
and in your views
def additem_view(request):
name = request.POST['expense_name']
expense_cost = request.POST['cost']
expense_date = request.POST['expense_date']
id= request.POST['id']
create=BudgetInfo.objects.create(id=id,items=name,cost=expense_cost,date_added=expense_date)
create.save()
return HttpResponseRedirect('app')
Your BudgetInfo model has a ForeignKey pointing to the your User model. When saving the BudgetInfo you never made the link to the (non-null) user.
If you want the script to refer to the "current user" (the user who actually made the request after logging in) you should simply use request.user:
BudgetInfo.objects.create(
user=request.user,
items=name,
cost=expense_cost,
date_added=expense_date,
)
If you're linking this to "some other user", you'll need to find that user first then link it the same way:
BudgetInfo.objects.create(
user=User.objects.get(username="smassey"), # for example
items=name,
cost=expense_cost,
date_added=expense_date,
)
So I'm trying to make a form with some data and an upload field. Django docs doesn't provide any good tutorial of doing this without forms.py. I don't want to use that.
I tried to adapt their tutorial with forms.py (https://docs.djangoproject.com/en/2.2/topics/http/file-uploads/) with my project but I'm getting an error.
"InMemoryUploadedFile' object is not callable"
I've tried searching it on google but I didn't find this error.
I obviously miss something, because when I used to do file uploads with Node I had to do more things, like setting file storage ect.
I just don't know how to handle this in django. So what am I missing and why do I get this error?
views.py
def incarcarecv(req):
context = {
'title': "title"
}
if req.method == 'POST':
nume = req.POST['nume']
prenume = req.POST['prenume']
telefon = req.POST['telefon']
email = req.POST['email']
CV = req.FILES['CV']
cvUpload = CV(solicitant = req.user, nume=nume, prenume=prenume, telefon=telefon, emailContact=email, CV=CV)
return render(req, "../templates/pagini/incarcare-cv.html", context)
models.py
class CV(models.Model):
solicitant = models.ForeignKey(User, on_delete=models.CASCADE)
dataUploadCV = models.DateField(auto_now_add=True)
nume = models.CharField(max_length=12)
prenume = models.CharField(max_length=12)
telefon = models.CharField(max_length=12)
emailContact = models.EmailField(max_length=40)
CV = models.FileField(upload_to='documents/%d/%m/%Y')
rezolvata = models.BooleanField(default=False)
def __str__(self):
return self.solicitant
html
{% extends 'base.html' %}
{% load static %}
{% block content %}
<div class="container container-centru">
<h1 class="heading-contact">Incarca CV</h1>
{% include 'partials/_alerts.html' %}
<form action="{% url 'incarcarecv' %}" method="POST" class="form-contact" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group">
<label for="inputnume" class="email-contact">Nume</label>
<input type="text" name="nume" class="form-control" id="inputnume" aria-describedby="emailHelp" placeholder="Introdu nume">
</div>
<div class="form-group">
<label for="inputprenume" class="email-contact">Prenume</label>
<input type="text" name="prenume" class="form-control" id="inputprenume" aria-describedby="emailHelp" placeholder="Introdu prenume">
</div>
<div class="form-group">
<label for="inputtelefon" class="email-contact">Telefon</label>
<input type="text" name="telefon" class="form-control" id="inputtelefon" aria-describedby="emailHelp" placeholder="Introdu telefon">
</div>
<div class="form-group">
<label for="inputemail" class="email-contact">Email</label>
<input type="email" name="email" class="form-control" id="inputemail" aria-describedby="emailHelp" placeholder="Introdu email">
</div>
<div class="form-group">
<label for="inputcv" class="email-contact">CV</label>
<input type="file" name="CV" class="form-control" id="inputemail" aria-describedby="emailHelp">
</div>
<div class="form-group form-group-custom">
<input type="submit" value="Trimite" class="btn btn-secondary btn-block btn-login-custom">
<input type="submit" value="Resetează câmpurile" class="btn btn-secondary btn-block btn-reset-custom">
</div>
</form>
</div>
{% endblock %}
Let me translate: name = last name, prenume = first name, telefon = phone.
So how can I handle files in this situation and without using forms.py? As I said, django doesn't provide any tutorial on this.
Thanks!
In your view, you shadow the CV model, by defining a local variable named CV. Indeed, you write:
CV = req.FILES['CV']
So in this view, CV does not refer to the model CV, but to the file, later you then call the constructor of the model CV(..), but you thus call the file handler instead.
def incarcarecv(req):
context = {
'title': 'title'
}
if req.method == 'POST':
nume = req.POST['nume']
prenume = req.POST['prenume']
telefon = req.POST['telefon']
email = req.POST['email']
cv = req.FILES['CV']
cv_upload = CV(
solicitant=req.user,
nume=nume,
prenume=prenume,
telefon=telefon,
emailContact=email,
)
cv_upload.cv.save(cv.name, cv)
cv_upload.save()
return render(req, '../templates/pagini/incarcare-cv.html', context)
You will need to cv_upload.save(), since otherwise you construct a CV object, but you did not store in in the database.
That being said, I strongly advise you to use a Form, here it looks like a simple ModelForm will be sufficient. A form also can validate the input, and produce errors that you can send back to the user about what is missing.
By using the PEP-8 naming conventions, it is also less likely that such name clashes will occur.
You also should, in case of a successful POST request, redirect to a page. This is the Post/Redirect/Get web development pattern. Otherwise in case the submission was successful, if you render a page, and the user refreshes the page in the browser, the browser will make the same POST request.
I have a simple form such as:
<form action = "{% url 'endresult' %}" form method = "POST">
{% csrf_token %}
<div class="well">
<h4 style="margin-top: 0"><strong> Student Details </strong></h4>
<div class="row">
<div class="form-group col-md-4">
<label/> Student ID
<input class="form-control" type="text" name = "studentpost" placeholder= "{{student.studentid}}" readonly>
</div>
</form>
</div>
The student ID does show up in my form, but when I try to get the results from endresult it shows up as a blank, if i try to call the studentid i get none. Why is this?
def endresult(request):
postedstudent = request.POST.get('studentpost')
print(f"postedstudent : {postedstudent }")
studentid = request.POST.get('student.studentid')
print(f"studentid : {studentid }")
return render(request, 'submitted.html')
Here is my output:
postedstudent:
studentid: None
Placeholder values are just that, placeholders. They are replaced by whatever is entered into the field, and are not submitted wth the form.
If you want a value to be prepopulated so that it is submitted, you should use the value attribute instead.
I have no idea why you think request.POST.get('student.studentid') would give a value, though.
Update multiple documents in django-mongodb with user inputs
I have a form which is meant to update all the price attribute of the objects in the product_details collection of my mongoDB.It is like Bulk price updating feature.I have tried few but finding it difficult.
Please suggest the method to do so in django.
How can I update the price of multiple products using the same form and view?
price.html
<form class="col s12" action="{% url "bulk" %}" method="POST">{% csrf_token %}
<button class="btn waves-effect waves-light" type="submit" name="action">Update<i class="material-icons right">cloud</i>
</button>
{% for r in result %}
<div class="col s6 m7">
<div class="card horizontal">
<div class="card-image" >
<img class ="materialboxed" width="650" src="{{r.ppro}}" style="width:100px;
height:150px;
max-width:100%;
max-height:100%;" >
</div>
<div class="card-stacked">
<div class="card-content">
<p style="font-size:15px;">{{r.ptitle}}<br>{{r.price}}</p>
</div>
<div class="card-action">
<div class="input-field col s4">
<input id="input_text" type="text" name=price value="{{r.price}}" data-length="10">
<label for="input_text">Price</label>
</div>
</div>
</div>
</div>
</div>
{% endfor %}
</form>
</div>
views.py
def bulk_price(request):
product_list= user_db.product_details.find({"shop_id":request.session["_id"]})
user_data = user_db.store_details.find_one({"_id":request.session["_id"]})
if product_list is not None:
return render(request,'price.html',{'result':product_list,'status':user_data['status']})
return render(request,'price.html')
mongoDB structure of product_details object
First of all, your input field name should be unique, you can use product id as name -
<input id="input_text" type="text" name="{{r.object_id}}" value="{{r.price}}" data-length="10">
Now, in the Django view, you can iterate through all the post data received from the form and update the database. Here is the code that should work -
def bulk_price(request):
#If request method is POST, update the database
if request.method == "POST":
for key in request.POST: #Iterate through POST variables
value = request.POST[key]
try:
objectId = ObjectId(key)
except Exeption as e:
#The key is not a valid object id, it might be csrfmiddlewaretoken or some other post data
continue
user_db.product_details.update_one(
{'_id': objectId},
{'$set': {'price': value}},
upsert=False
)
#Render the update price page
product_list= user_db.product_details.find({"shop_id":request.session["_id"]})
user_data = user_db.store_details.find_one({"_id":request.session["_id"]})
if product_list is not None:
return render(request,'price.html',{'result':product_list,'status':user_data['status']})
return render(request,'price.html')
Don't forget to import ObjectId():
from bson.objectid import ObjectId
Note: To use MongoDB ObjectID in Django template, you will need a custom template filter. Refer to this answer - https://stackoverflow.com/a/24936772/8039601
SOLVED by Peter DeGlopper:
Thank you for your help it solved my issues, I really do appreciate it. I was banging my head against the table.
I didn't have to change my ModelForm. Looking at the HTML source I noticed in the input tag checked="checked" A subnet was being outputted as checked but it wasn't showing checked in my browser. This was in Firefox 24.2.0 in CentOS (On a VM), so I went to my Windows 7 host and loaded up Firefox 26.0 it worked, and worked fine in IE8 as well. That was weird, but it explains your confusion of that it should just work.
For saving the fields thanks to you I now see how I was over thinking it. And I am able to update the M2M field. I updated the TagUpdateView below to show the working code.
I have 2 issues with trying use an UpdateView with a M2M field...
The currently "tagged" subnets dont show up as checked in my template
How would I handle updating the M2M relationship in my TagUpdateView by overriding form_valid?
Any insight would be greatly appreciated.
Thanks.
Tag m2m models.py:
class Tag(models.Model):
tag = models.CharField(max_length=120)
group = models.ForeignKey(Group)
description = models.TextField(max_length=500)
subnet = models.ManyToManyField(Subnet, null=True, blank=True)
date_created = models.DateTimeField()
created_by = models.ForeignKey(User, related_name='tag_created_by')
date_modified = models.DateTimeField(auto_now=True)
modified_by = models.ForeignKey(User, related_name='tag_modified_by')
def __unicode__(self):
return self.tag
Tag ModelForm:
class TagForm(forms.ModelForm):
subnet = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple(), required=True, queryset=Subnet.objects.all())
class Meta:
model = Tag
exclude = ('date_created', 'created_by', 'date_modified', 'modified_by')
Tag views.py:
class TagUpdateView(UpdateView):
template_name = 'tag_update.html'
model = Tag
form_class = TagForm
def form_valid(self, form):
update_tag = form.save(commit=False)
update_tag.modified_by = self.request.user
update_tag.save()
form.save_m2m()
return super(TagUpdateView, self).form_valid(form)
My template "tag_update.html":
{% extends 'base.html' %}
{% load widget_tweaks %}
{% block title %}Tag {{ object.tag }} Update{% endblock %}
{% block content %}
<h1>Tag {{ object.tag }} Update</h1>
<br />
<form action="" method="post" role="form">{% csrf_token %}
<div class="row">
<div class="col-sm-4">
<div class="form-group">
<label for="id_tag">Tag Name</label>
{% render_field form.tag placeholder=form.tag.label class="form-control" %}
</div>
</div>
</div>
<div class="row">
<div class="col-sm-2">
<div class="form-group">
<label for="id_group">Group</label>
{% render_field form.group placeholder=form.group.label class="form-control"%}
</div>
</div>
</div>
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label for="id_description">Description</label>
{% render_field form.description placeholder=form.description.label class="form-control" rows="5" %}
</div>
</div>
</div>
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label for="id_checkbox">Link to Subnets</label>
{{ form.subnet }}
</div>
</div>
</div>
<br />
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<br />
{% endblock %}
You're overthinking it. Handling this kind of relationship can be a little bit complicated if you need to track information on the relationship model itself (like a modified timestamp for when a particular subnet/tag pair was created) but for the model relationships you've shown here, form.save_m2m() is sufficient - it handles the m2m relationship for you.
You wouldn't even need that if you didn't need to use commit=False on your initial form save so you can set your modified_by field.
For prepopulation - mostly this looks to me like it should follow the normal behavior and prepopulate. I would probably just use the widget class rather than explicitly instantiating it (widget=forms.CheckboxSelectMultiple rather than widget=forms.CheckboxSelectMultiple()) but I don't see why that would affect it.
For both problems, you might have good results by starting with a simple ModelForm with no customizations on subnet, just exclude set. Once that's working, put in the special view code to handle modified_by. Once that's working, change to a custom widget declaration for subnet - maybe initially using the meta widgets override dictionary rather than a custom field declaration for the first pass.