I got a form page to edit my objects from database, but when I access them with the edit button it goes to the url http://localhost:8000/acoes/edit/1, but I cannot see the object details in the form field. It is just empty as if I was going to create a new object (and it creates if I try)
Any suggestion? Every post and question that I found online states that the code would work being just like this, but it isnt.
on the template acoes_form.html
<form method="post">
<div class="form-group">
{% csrf_token %}
{{form.as_p}}
</div>
<input type="submit" value="Gravar dados" class="btn btn-success" />
</form>
on views.py
#login_required(login_url="/login")
def acoes_edit(request, pk, template_name='acoes/acoes_form.html'):
if request.user.is_superuser:
acoes= get_object_or_404(Acoes, pk=pk)
else:
acoes= get_object_or_404(Acoes, pk=pk, user=request.user)
form = AcoesForm(request.POST or None, instance=acoes)
if form.is_valid():
form.save()
return redirect('acoes_list')
return render(request, template_name, {'form':AcoesForm})
on forms.py
class AcoesForm(ModelForm):
#bunch of fields definitions
#...
#
class Meta:
model = Acoes
fields = ['id_pedido','bl_msg','tb_msg','bl_shell','tb_shell','obs','ativo']
Change your view as follows:
#login_required(login_url="/login")
def acoes_edit(request, pk, template_name='acoes/acoes_form.html'):
if request.user.is_superuser:
acoes= get_object_or_404(Acoes, pk=pk)
else:
acoes= get_object_or_404(Acoes, pk=pk, user=request.user)
form = AcoesForm(request.POST or None, instance=acoes)
if form.is_valid():
form.save()
return redirect('acoes_list')
return render(request, template_name, {'form': form})
You were accidentally referring to the form class rather than the form instance.
On a side note you may want to only save the form if the person POSTed data to the view e.g.
#login_required(login_url="/login")
def acoes_edit(request, pk, template_name='acoes/acoes_form.html'):
if request.user.is_superuser:
acoes= get_object_or_404(Acoes, pk=pk)
else:
acoes= get_object_or_404(Acoes, pk=pk, user=request.user)
form = AcoesForm(request.POST or None, instance=acoes)
if request.method == 'POST' and form.is_valid():
form.save()
return redirect('acoes_list')
return render(request, template_name, {'form': form})
The error is in the last line, you are passing the form class and not the form object.
return render(request, template_name, {'form':form})
Related
here is my code. I am using Modelforms and Crispy forms library to generate form.
when I click form submit everything is saved, except Category(manytomanyfield), that I have to specify manually from admin panel.
NOTE: I FOUND SOME SOLUTIONS ONLINE to do form.save_m2m() but I get Object has no attribute save_m2m()
my modelform.
from django.forms import ModelForm
from .models import Article
class ArticleForm (ModelForm):
class Meta:
model = Article
fields = '__all__'
exclude = ('user',)
my views.
def create(request):
if request.method =="POST":
form = ArticleForm(request.POST, request.FILES)
if form.is_valid():
form = form.save(commit=False)
form.user = request.user
return redirect('home')
form = ArticleForm()
context = {'form': form}
return render(request, 'article_form.html', context)
my template.
<form action="" enctype="multipart/form-data" method="post">
{% csrf_token %}
{{form|crispy}}
<button type="submit" class="btn btn-primary">Submit</button>
</form>
You're overwriting form:
The code should be:
if form.is_valid():
#form.save() returns a model instance, not another form
article = form.save(commit=False)
article.user = request.user
article.save()
form.save_m2m()
...
I couldn't get my input data to many-to-many field data via the HTML form. How to solve this?
This is my code:
models.py
class SetStaffSchedule(models.Model): # generated work for staffs by admins
schedule = models.ManyToManyField('Staff')
shift = models.DateTimeField("Shift")
detail = models.TextField("Task Detail", max_length=200)
def __str__(self):
return self.shift
def __str__(self):
return self.detail
forms.py
from django import forms
from attendance.models import SetStaffSchedule, Staff
class SetStaffScheduleForm(forms.ModelForm):
class Meta:
model = SetStaffSchedule
fields = ['schedule','shift', 'detail']
views.py
def schedules(request): # getting schedules for staffs' work
all_schedules = SetStaffSchedule.objects.all()
context = {
'all_schedules': all_schedules
}
return render(request, 'getschedule.html', context)
def post(request): # posting schedules for staffs' work
form = SetStaffScheduleForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
instance.save();
return redirect ('schedules')
return render(request, 'post_schedules.html', {"form": form})
post_schedules.html
{% csrf_token %}
{{ form.as_p }}
You need to handle the case where the request method is "GET" so that you can render the form without any validation being run. If the user then submits the form as a "POST" you should run the validation/saving
def create_staff_schedule(request): # posting schedules for staffs' work
if request.method == 'GET':
form = SetStaffScheduleForm()
else: # POST
form = SetStaffScheduleForm(request.POST)
if form.is_valid():
form.save()
return redirect('schedules')
return render(request, 'post_schedules.html', {"form": form})
You need to also wrap the form in a form tag with the method set to "post"
<form method="post">
{% csrf_token %}
{{ form.as_p }}
</form>
This may possibly be a duplicate of this answer. Currently, i'm working on updating an object using the same model form that is used to create the object.
my views.py looks like: (as from the answer):
def newpost(request):
form = PostForm(request.POST)
if request.method == "POST":
if form.is_valid():
obj = form.save(commit=False)
obj.save()
return redirect('newpost')
return render(request, 'console/newpost.html', {'form':form})
def editpost(request, pk):
obj = Post.objects.get(id=pk)
form = PostForm(instance=obj)
if request.method == "POST":
if form.is_valid():
obj = form.save(commit=False)
obj.save()
return redirect('editpost')
return render(request, 'console/editpost.html', {'form':form})
And my html form in editpost looks like:
<form method="POST" action="{% url 'newpost' %}">
{% csrf_token %}
{{form.as_p}}
<button type="submit"> Submit</button>
</form>
and my urls.py looks like:
path('console/post/', c_views.newpost, name='newpost'),
path('console/post/<int:pk>/', c_views.editpost, name='editpost'),
And the above codes works perfectly fine, but creates a new instance, with the data of the object taken from pk.
I added a obj.delete() code like this:
def editpost(request, pk):
obj = Post.objects.get(id=pk)
form = PostForm(instance=obj)
obj.delete()
if request.method == "POST":
if form.is_valid():
obj = form.save(commit=False)
obj.save()
return redirect('editpost')
return render(request, 'console/editpost.html', {'form':form})
This code gives me the exact thing i wanted, but i know it's not a good practice. My question here is, is this a correct way or am i lagging somewhere.
I know the action in my editpost html should not be {% url 'newpost' %}, but if i use {% url 'editpost' %} i don't know how to pass the pk value inside the url tag. Can anyone suggest me the correct way?
Each of your views should accept GET and POST methods, when the method is GET the form is instantiated with no request.POST data passed to it and the form is just rendered.
def newpost(request):
if request.method == 'GET':
form = PostForm()
else: # POST
form = PostForm(request.POST)
if form.is_valid():
form.save()
return redirect('newpost')
return render(request, 'console/newpost.html', {'form':form})
def editpost(request, pk):
obj = Post.objects.get(id=pk)
if request.method == 'GET':
form = PostForm(instance=obj)
else: # POST
form = PostForm(request.POST, instance=obj)
if form.is_valid():
form.save()
return redirect('editpost')
return render(request, 'console/editpost.html', {'form':form})
<form method="POST">
If you do not set the "action" attribute on a form it will submit the data to the same URL that the browser is currently on. This way you can use the same template for both views
I'm making a little personal project using Django framework and I get one question while making login view with django form.
I was struggled to show form error messages in my template, and I found a cause in my view.
This is view that showing error message
def login_view(request):
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
form.login(request)
return redirect('/')
else:
form = LoginForm()
context = {
'form': form,
}
return render(request, 'member/login.html', context=context)
another view that dosen't showing error message
def login_view(request):
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
form.login(request)
return redirect('/')
form = LoginForm()
context = {
'form': form,
}
return render(request, 'member/login.html', context=context)
and this is my template
<form action="{% url 'login' %}" method="post">
{% csrf_token %}
{{ form.username}}
{{ form.password }}
{{ form.non_field_errors }}
<button id="login-btn" class="btn btn-default" type="submit">login</button>
The difference is just using elsephrase or not in view.
I think whether using elsephrase or not, there two views have logically same result... I don't understand difference of those two views.
Is there any clue to understand the differece of those two views?..
Thanks
You're overwriting the POST form by defining the form at the end. Load the blank form first
def login_view(request):
form = LoginForm()
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
form.login(request)
return redirect('/')
context = {
'form': form,
}
return render(request, 'member/login.html', context=context)
The form field won't show up in the browser. There is only the submit button showing up.
views.py code:
def vote(request, pk):
# check if request is post
if request.method == 'POST':
# create a form and populate it with data from request
form = forms.Vote(request.POST)
if form.is_valid():
fact = Fact.objects.get(pk=pk)
fact.votes += int(form.cleaned_data['vote'])
fact.save()
return HttpResponseRedirect(reverse(
'facts:detail',
args=(pk,)
))
else:
form = forms.Vote()
return render(request, 'facts/fact_detail.html', {'form': form})
template(fact_detail.html) code:
<form method='POST'>
{% csrf_token %}
{{ form }}
<input type="submit" value="vote" />
</form>
Form class(forms.py) code:
VOTE_CHOICES = [
(1, 'upvote'),
(0, 'downvote')
]
class Vote(forms.Form):
vote = forms.ChoiceField(choices=VOTE_CHOICES, widget=forms.RadioSelect())
In views.py for the vote method initialize the form variable locally, before passing it as a parameter.
def vote(request, pk):
form=""
//rest of the code//
return render(request, 'facts/fact_detail.html', {'form': form})
I recommend check generic editing views from django documentation I think it has the solution
[ https://docs.djangoproject.com/en/1.11/ref/class-based-views/generic-editing/#createview][1]