How to edit an object using model form in django? - python

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

Related

Django Form Not Saving the Data

I've imported this from django.contrib.auth.forms import UserCreationForm
used csrf_token in the form but still when I hit submit the page reloads but doesn't save the data to database.
def signup(req):
if req.method == 'POST':
form = UserCreationForm(req.POST)
if form.is_valid():
form.save()
form = UserCreationForm()
reg_con={
'regform': form
}
return render(req, 'signup.html', reg_con)
form
<form action="." method="POST">
{% csrf_token %}
{{ regform.as_ul }}
<input type="submit" value="Sign Up">
</form>
This is normally because something is wrong with your form the problem is however that you each time construct a new form, and you thus can not see what went wrong. You should only create a new form in case it is a GET request, so:
def signup(req):
if req.method == 'POST':
form = UserCreationForm(req.POST)
if form.is_valid():
form.save()
else:
form = UserCreationForm()
reg_con={
'regform': form
}
return render(req, 'signup.html', reg_con)
Try removing the action attribute from your form tag. Also don't forget to redirect after calling form.save()

How to show many-to-many fields from form on on HTML form in Django

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>

Passing Dropdown Value To URL in Django

I am rendering a dropdown which displays a list of integers. This is the only field in the form/view. Once that form is submitted, the integer selected should be passed to the URL of the next view which is rendered on submission of the previous form.
I am getting a 404 when I attempt this.
Here is what I am currently trying:
forms.py
#this is the dropdown field
class ManifestDropDown(forms.Form):
reference = forms.ModelChoiceField(queryset=Orders.objects.values_list('reference', flat=True).distinct(),
empty_label=None)
views.py
#this is the view where the dropdown is submitted
def manifest_references(request):
if request.method == 'POST':
form = ManifestDropDown(request.POST)
if form.is_valid():
reference_id = form.cleaned_data.get('reference')
form.save()
return render('manifest', reference_id=reference_id)
query_results = Orders.objects.all()
reference_list = ManifestDropDown()
context = {
'query_results': query_results,
'reference_list': reference_list,
}
return render(request, 'manifest_references.html', context)
#this is the view where the value should be displayed in the url
def manifest(request, reference_id):
form = CreateManifestForm(request.POST)
if request.method == "POST":
....
data = Manifests.objects.all().filter(reference__reference=reference_id)
form = CreateManifestForm(initial={
'reference': Orders.objects.get(reference=reference_id),
})
total_cases = Manifests.objects.filter(reference__reference=reference_id).aggregate(Sum('cases'))
context = {
'reference_id': reference_id,
'form': form,
'data': data,
'total_cases': total_cases['cases__sum'],
}
return render(request, 'manifest_readonly.html', context)
urls.py
#url which displays the manifest view above
url(r'^manifest/(?P<reference_id>\d+)/$', manifest, name='manifest'),
url(r'^references_manifests', manifest_references, name='references_manifests'),
manifest_references.html
<div class="container">
<br>
<br>
<br>
<form method="POST" action="references_manifests">
{% csrf_token %}
{{ reference_list }}
<button type="submit" class="btn btn-primary" name="button">Create Proforma</button>
</form>
</div>
To dynamically change the URL that you're actually submitting to, you would need to use JavaScript.
But an alternative is to submit back to the manifest_references view, then redirect from there to manifest. (Note, you should always be redirecting, not rendering, after a successful submission anyway. And no need to call form.save(), this isn't a modelform so there is nothing to save.)
def manifest_references(request):
if request.method == 'POST':
form = ManifestDropDown(request.POST)
if form.is_valid():
reference_id = form.cleaned_data.get('reference')
return redirect('manifest', reference_id=reference_id)
You can do two things:
Call the manifest view directly.
Redirect the user to the manifest page.
The first one should be done like this:
if form.is_valid():
reference_id = form.cleaned_data.get('reference')
form.save()
return manifest(request, reference_id)
The second one can be done like this:
if form.is_valid():
reference_id = form.cleaned_data.get('reference')
form.save()
return HttpResponseRedirect(reverse('manifest', reference_id = reference_id))
It doesn't really matter which one you do, although I would recomment redirecting the user to the correct page, because then a refresh will not resend the form the user has entered.

django form view show error or not

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)

Edit view on Django not displaying object into page

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})

Categories