I am making a simple todolist application but while I am trying to create user specific pages, I am unable to add a new task probably beacause database is not getting all required datas(i.e. owner of the task).
models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class value(models.Model):
task=models.CharField(max_length=200)
complete=models.BooleanField(default=False)
created=models.DateTimeField(auto_now_add=True)
owner=models.ForeignKey(User,on_delete=models.PROTECT)
def __str__(self):
return self.task
views.py
from http.client import HTTPResponse
from urllib import response
from django.shortcuts import render,redirect
from todo.models import value
from django.http import HttpResponseRedirect
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
# Create your views here.
from .forms import TitleForm
from django.urls import reverse
from django.contrib.auth.models import User
def home(request):
values=value.objects.all()
form=TitleForm()
if request.method=='POST':
form=TitleForm(request.POST)
if form.is_valid():
new_data=form.save(commit=False)
new_data.owner=request.user()
new_data.save()
return HttpResponseRedirect('/')
context={'form':form,'values':values}
return render(request,'home.html',context)
#update
def update(request,id):
ggwp=value.objects.get(id=id)
form=TitleForm(instance=ggwp)
if request.method == 'POST':
form=TitleForm(request.POST,instance=ggwp)
if form.is_valid:
form.save()
return redirect('home')
context={'form':form,}
return render(request,'update.html',context)
#delete
def delete_data(request, id ):
if request.method=="POST":
ggwp=value.objects.get(id=id)
ggwp.delete()
return HttpResponseRedirect(reverse('deldata', kwargs={'id':id}))
return redirect("/")
forms.py
from django import forms
from django.forms import ModelForm
from .models import value
from django import forms
class TitleForm(forms.ModelForm):
class Meta:
model= value
fields='__all__'
urls.py(app)
from django.conf.urls import url
from django.urls import path
from . import views
urlpatterns=[
path('',views.home,name='home'),
path('delete/<str:id>', views.delete_data,name='deldata'),
path('update/<str:id>',views.update,name='update')
]
home.html(main page)
<form method="POST">
{% if user.is_authenticated %}
Hello,{{user.username}}<br>
Logout
{% else%}
Register
login
{% endif %}
</form>
<div class="p-3 mb-2 bg-warning text-dark" style="text-align: center;">
<form action="/" method="post" >
{% csrf_token %}
{{form.task}}
<input class='btn btm-sm btn-info' type='submit' name='add' value="add" >
</form>
{% for val in values %}
{% if val.complete == True %}
<s>{{val}}</s>
{% else %}
<span>{{val}}</span>
{% endif %}
<form action="{% url 'deldata' val.id %}" method="POST" class="in-line">
{% csrf_token %}
<input class='btn btm-sm btn-danger' type="submit" name="delete" value="delete">
<a class='btn btm-sm btn-info' href="{% url 'update' val.id %}" >Update</a>
</form>
{% endfor %}
</div>
Home.html looks like this:
todo
When i want to add a task and click on add, nothing really happens. It only redirects back to same page but not data is inserted in database.
If there are problems in questions, I am really sorry!
Home.html :
<div class = "divname">
{% if user.is_authenticated %}
Hello,{{user.username}}<br>
Logout
{% else%}
Register
login
{% endif %}
</div>
<div class="p-3 mb-2 bg-warning text-dark" style="text-align: center;">
<form method="POST" >
{% csrf_token %}
{{form}}
<input class='btn btm-sm btn-info' type='submit' name='add' value="add" >
</form>
{% for val in values %}
{% if val.complete == True %}
<s>{{val}}</s>
{% else %}
<span>{{val}}</span>
{% endif %}
<form action="{% url 'deldata' val.id %}" method="POST" class="in-line">
{% csrf_token %}
<input class='btn btm-sm btn-danger' type="submit" name="delete" value="delete">
<a class='btn btm-sm btn-info' href="{% url 'update' val.id %}" >Update</a>
</form>
{% endfor %}
</div>
UPDATE1 : EXCLUDING USER IN FORM AND ADDING THE CURRENT USER IN VIEWS
#Do not add Owner into the model form fields
forms.py:
from django import forms
from django.forms import ModelForm
from .models import value
from django import forms
class TitleForm(forms.ModelForm):
class Meta:
model= value
fields=['task', 'complete', 'created']
Views.py:
def home(request):
values=value.objects.all()
form=TitleForm()
if request.method=='POST':
form=TitleForm(request.POST)
if form.is_valid():
new_data=form.save(commit=False)
new_data.owner=request.user
new_data.save()
return HttpResponseRedirect('/')
context={'form':form,'values':values}
return render(request,'home.html',context)
Related
I'm a new in Django and trying to do a app but now I'm having this error: "Invalid block tag on line 24: 'form.as_p', expected 'endblock'."
TEMPLATE
{% extends "base.html" %}
{% block title %}
<title>Tarefas</title>
{% endblock title %}
{% block content %}
<div class="content">
{% if messages %}
<div class="container">
<br>
{% for message in messages %}
<div class="alert alert-info" role="alert">
{{message}}
</div>
{% endfor %}
</div>
{% endif %}
<div class="container tasks-box">
<table class="table table-striped">
<form method='POST'>
{% csrf_token %}
{% form.as_p %}
<button type="submit" class="btn btn-secondary btn-sec">Adicionar</button>
</form>
[...]
forms.py
from django.forms import ModelForm
from todolist.models import Tasks
class TaskForm(ModelForm):
class Meta:
model = Tasks
fields = ['task','responsible']
views.py
from django.shortcuts import render, redirect
from django.http import HttpResponse
from todolist.models import Tasks
from todolist.forms import TaskForm
from django.contrib import messages
from django.contrib.auth.decorators import login_required
#login_required
def todolist(request):
if request.method == 'POST':
form = TaskForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
instance.manager = request.user
instance.save()
messages.success(request,("Tarefa adicionada"))
return redirect('todolist')
else:
form = TaskForm
all_tasks = Tasks.objects.filter(manager=request.user)
all_users = Tasks.objects.all()
return render(request,'todolist.html',{ 'form':form,
'all_tasks':all_tasks,
'all_users':all_users})
models.py
from django.db import models
from django.contrib.auth.models import User
from django.contrib.auth import get_user_model
# Create your models here.
User = get_user_model()
class Tasks(models.Model):
manager = models.ForeignKey(User, on_delete=models.CASCADE,default=None, related_name='tasks_manager')
task = models.CharField(max_length=300)
done = models.BooleanField(default=False)
responsible = models.ForeignKey(User, on_delete=models.CASCADE, default=None, related_name='tasks_responsible', blank=True, null=True)
def __str__(self):
return self.task
I tryed don't use {{ form }} tag in template and thats work.
I think the problem is in views, but i can't figure out why.
Someone can help me?
From form rendering options as documented
All you need to do to get your form into a template is to place the form instance into the template context. So if your form is called form in the context, {{ form }} will render its and elements appropriately.
There are other output options though for the / pairs:
{{ form.as_table }} will render them as table cells wrapped in <tr> tags
{{ form.as_p }} will render them wrapped in <p> tags
{{ form.as_ul }} will render them wrapped in <li> tags
So you have a typo error in {% form.as_p %} just replace this with {{ form.as_p }}
I am a beginner in Django
I want to save a form data in database but i am not able to save, followed some tutorials also.
form.py:
from django.forms import ModelForm
from .models import *
class listsForm(ModelForm):
class Meta:
model = todo
fields = "__all__"
views.py:
from django.shortcuts import render
from .models import *
from .form import *
def index(request):
lists = todo.objects.all()
form = listsForm()
context = {
'lists':lists,
'form':form,
}
if request.method == 'POST':
form = listsForm(request.POST)
if form.is_valid:
form.save()
return render(request, 'index.html', context)
models.py:
from django.db import models
class todo(models.Model):
title = models.CharField(max_length=200)
description = models.TextField(null=True, blank=True)
created = models.DateField(auto_now_add=True)
def __str__(self):
return self.title
Why are you rendering listsForm?
Your form should be in the template not rendered!
In index.html, your form should looks like the following:
<form action="{% url 'create_todo' %}" method="POST">
{% csrf_token %}
<div class="form-group">
<label for="title">Title</label>
<input type="text" name="title" class="form-control" id="title" required></div>
<div class="form-group">
<label for="Description">Description</label>
<textarea name="description" class="form-control" id="description" ></textarea></div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
In views.py
def index(request):
return render(request, 'index.html')
def create_todo(request):
if request.method == 'POST':
form = listsForm(request.POST)
if form.is_valid():
form.save()
return redirect('index')
In urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('create_todo/', views.create_todo, name='create_todo')
]
You will still need to render existed todos, preferably in another template.
So in views.py
def alltodos(request):
todos = Todo.objects.all()
return render(request, 'index.html', {'todos':todos})
In index.html, above form or after it, it doesn't matter, just for clear visibility
<div class="row justify-content-center mt-5">
<div class="col-md-10">
{% if todos %}
<div class="list-group">
{% for todo in todos %}
<a class="list-group-item list-group-item-action><b>{{ todo.title }}</b>{{ todo.description|truncatechars:30 }}{% endif %}</a>
{% endfor %}
</div>
{% else %}
<div class="text-center">
<h2>Looks like you don't have any todos!</h2>
<br>
</div>
{% endif %}
</div>
</div>
In urls.py add
path('todos', views.alltodos, name='alltodos'),
Advanced project of mine
I have find out why it was not working,
I was using <input type="button"> for submit button
but when I changed it to <button type="submit"> it works.
so i'm working on little django application where users can view and modify there profile ,but i didn't know how to provide a button under the profile picture that allows the user to choose a new one and when he chooses it redirect him to the same page with the new profile picture ,any help or ideas will be usefull , tnks !!
here's what i tried :
forms.py
class picture_form(forms.ModelForm):
class Meta:
model=Profile
fields=('image',)
views.py
def profile(request):
if request.method == 'POST':
form = picture_form(request.POST, request.FILES)
if form.is_valid():
profile = Profile.objects.get(user=request.user)
profile.image = form.cleaned_data['image']
profile.save()
return redirect(reverse('profile'))
else:
for usr in User.objects.all():
if request.user.get_full_name() == usr.get_full_name():
prf = Profile.objects.filter(user=usr)
form = picture_form()
return render(request, 'store/profile.html', {'profile': prf, 'form': form})
template
{% if prf.image %}
<div class="profile-img">
<img src="{{ prf.image.url }}" id="prf_img" alt=""/>
</div>
{% else %}
<div class="profile-img">
<img src="{% static 'img/empty-profile-picture.png' %}" id="prf_img" alt=""/>
</div>
{% endif %}
<!--<a href="{% url 'upload_picture' %}"> <div class="file btn btn-lg " >
Change Photo
<input type="file" name="file"/>
</div></a> -->
<form method="post" action="{% url 'profile' %}" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" class="btn btn-outline-success" value="upload">
</form>
</div>
Django has an awesome generic editing view called UpdateView. You can do something like this:
models.py
class Profile(models.Model):
image = models.ImageField()
views.py
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic.edit import UpdateView
#method_decorator(login_required, name='dispatch')
class UpdateProfileView(UpdateView):
model = Profile
fields = ['image']
template_name_suffix = '_update_form'
success_url = ''
def form_valid(self, form):
form.instance.user = self.request.user
return super().form_valid(form)
profile_update_form.html
<form method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Update">
</form>
urls.py
from . import views
path('<int:pk>/update/', views.UpdateProfileView.as_view(), name='profile-update')
I have this code on my template:
{% extends "base.html" %}
{% block content %}
<div style="padding:40px;margin:40px;border:1px solid #ccc">
<h1>picture</h1>
<form action="" method="post" enctype="multipart/form-data"> <!--{% url 'imageupload' %}-->
{% csrf_token %} {{form}}
<input type="submit" value="Upload" />
</form>
{% for img in images %}
{{forloop.counter}}.{{ img.pic.name }}
({{img.upload_date}})<hr />
{% endfor %}
</div>
{% endblock content %}
Although I have doubts with the form action but anyways.
The problem is that when I click on submit button, it takes me to a blank page, no pop-up to actually upload the image, nothing.
Is there some example I should follow to accomplish this?
Also, this is just a proof test, but I'd like to know if a model and/or form is actually needed for it to work?
EDIT
Okay, by editing the input line like this <input type="file" name='input_name' /> it actually opens the file pop-up, but obviously it doesn't upload anything, it needs like a submit button or something, so, now it looks like this:
{% extends "base.html" %}
{% block content %}
<div style="padding:40px;margin:40px;border:1px solid #ccc">
<h1>picture</h1>
<form action="" method="post" enctype="multipart/form-data"> <!--{% url 'imageupload' %} -->
{% csrf_token %} {{form}}
<input type="file" name='input_name' />
<input type="submit" value="Upload" />
</form>
{% for img in images %}
{{forloop.counter}}.{{ img.pic.name }}
({{img.upload_date}})<hr />
{% endfor %}
{% endblock content %}
But when I click on submit, it keeps sending me to a blank page, so, the value on submit, which is Upload, comes from this model:
from django.db import models
from django.forms import ModelForm
class Upload(models.Model):
pic = models.FileField(upload_to="static/")
upload_date=models.DateTimeField(auto_now_add =True)
class UploadForm(ModelForm):
class Meta:
model = Upload
fields = ('pic',)
And on my views.py:
from django.shortcuts import render
from uploader.models import UploadForm,Upload
from django.http import HttpResponseRedirect
from django.urls import reverse
def home(request):
if request.method=="POST":
img = UploadForm(request.POST, request.FILES)
if img.is_valid():
img.save()
return HttpResponseRedirect(reverse('imageupload'))
else:
img=UploadForm()
images=Upload.objects.all()
return render(request,'image_upload.html',{'form':img,'images':images})
And in my urls.py:
from django.conf import settings
from django.conf.urls import include, url
from django.conf.urls.static import static
from django.contrib import admin
from django.views.generic import TemplateView
from django.views import defaults as default_views
from uploader import views as uploader_views
urlpatterns = [...
some patterns...
url(r'^image_upload/', uploader_views.home, name='imageupload'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
I'm trying to get together code that uploads and deletes photos from a django/bootstrap carousel, as well as a database. However, I can't seem to get past this error:
TypeError at /alzheimers/delete
delete() takes exactly 2 arguments (1 given)
Can anyone help me? I'm kind of a noob at django, and writing this code is like pulling teeth, so any help would be greatly appreciated.
My code:
Carousel.html:
{% load staticfiles %}
{% load filename %}
<div class="container">
<div class="row">
<div class="col-md-12">
<div id="myCarousel" class="carousel slide" data-ride="carousel">
<div class="carousel-inner" role="listbox">
{% for document in documents %}
<div class="item {% if forloop.first %} active {% endif %}">
<div class="row">
<div class="col">
<li>{{document.docfile.name}}</li>
<img src = "{{STATIC_URL}}img/{{document|filename}}" >
<p align="center"><form style="text-align:center" action="{% url 'webportal:delete' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>{{ form.non_field_errors }}</p>
<p>{{ form.Document.label_tag }} {{ form.Document.help_text }}</p>
<p>
{{ form.Document.errors }}
{{ form.Document.docfile }}
</p>
<p><input type="submit" value="Delete" /></p>
</form></p>
</div>
</div>
</div>
{% endfor %}
</div>
<a class="left carousel-control" href="#myCarousel" role="button" data-slide="prev">
<span class="glyphicon glyphicon-chevron-left"></span>
<span class="sr-only">Previous</span>
</a>
<a class="right carousel-control" href="#myCarousel" role="button" data-slide="next">
<span class="glyphicon glyphicon-chevron-right"></span>
<span class="sr-only">Next</span>
</a>
</div>
<!-- /.carousel -->
</div>
</div>
<form action="{% url 'webportal:carousel' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>{{ form.non_field_errors }}</p>
<p>{{ form.docfile.label_tag }} {{ form.docfile.help_text }}</p>
<p>
{{ form.docfile.errors }}
{{ form.docfile }}
</p>
<p><input type="submit" value="Upload" /></p>
</form>
</div>
Views.py:
from django.shortcuts import render
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth import authenticate, login
from webportal.views.authentication import LoginForm
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.http import HttpResponseRedirect
from django.http import HttpResponse
from django.core.urlresolvers import reverse
from django.conf import settings
from webportal.forms.forms import DocumentForm
from webportal.models import Document, DeleteForm
is_server = True
def delete(request, my_id):
Deleted=get_object_or_404(Document, docfile=my_id)
if request.method=='POST':
form=DeleteForm(request.POST, instance=Deleted)
if form.is_valid():
Deleted.delete()
return HttpResponseRedirect('http://127.0.0.1:8000/alzheimers/')
else:
form=DeleteForm(instance=Deleted)
return render_to_response(
'webportal/index.html',
{'documents': documents, 'form': form,},
context_instance=RequestContext(request)
)
# Redirect to the document list after POST
def carousel(request):
# Handle file upload
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
newdoc = Document(docfile = request.FILES['docfile'])
newdoc.save()
# Redirect to the document list after POST
return HttpResponseRedirect('http://127.0.0.1:8000/alzheimers/')
else:
form = DocumentForm() # A empty, unbound form
# Load documents for the list page
documents = Document.objects.all()
#documents=DocumentForm().
# Render list page with the documents and the form
return render_to_response(
'webportal/index.html',
{'documents': documents, 'form': form,},
context_instance=RequestContext(request)
)
Models.py:
class Document(models.Model):
docfile = models.ImageField(upload_to='webportal/static/img/')
class DeleteForm(ModelForm):
class Meta:
model=Document
fields=[]
Forms.py:
class DocumentForm(forms.Form):
docfile = forms.ImageField(label='Select a file', help_text='max. 42 megabytes')
urls.py:
url(r'^delete', views.delete, name="delete"),
You are POSTing your object id through a form while your delete view expects it as an argument (my_id). Change it to:
def delete(request):
if request.method=='POST':
my_id = request.POST.get('id')
Deleted=get_object_or_404(Document, id=my_id)
...
As a side note, the Python convention is to use lowercase names for objects. Consider renaming Deleted to deleted.
Update: You also seem to have omitted to include the id of the object to be deleted in your form. Put the following line somewhere between your <form> and </form> tags:
<input type="hidden" name="id" value="{{ document.id }}" />