Model Forms not saving ManytoMany Field - python

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()
...

Related

Django forms: cannot access local variable 'form' where it is not associated with a value

Condition: I have a model, created an empty table in the database, and I'm trying to create an html form that will fill in the fields of the corresponding columns of the table.
And here's what my app looks like:
models.py
from django.db import models
class Cities(models.Model):
city = models.CharField(max_length=100)
def __str__(self):
return self.state
class Routes(models.Model):
route_name = models.CharField(max_length=50, default='Route')
lvl = models.IntegerField(default=0)
about = models.TextField(max_length=1500)
total_distance = models.IntegerField(default=0)
city = models.ForeignKey(Cities, on_delete=models.CASCADE)
forms.py
from django.forms import ModelForm
from .models import Routes
class RouteForm(ModelForm):
class Meta:
model = Routes
fields = '__all__'
views.py
from django.shortcuts import get_object_or_404, render
from django.http import HttpResponse
from routes_form.forms import RouteForm
def getAbout(request):
if request.method == 'POST':
form = RouteForm(request.POST)
if form.is_valid():
form.save()
return render(request, 'routes_form/form_page.html', {'form': form})
form.html
<form method="post">
{% csrf_token %}
<legend>
<h2>About</h2>
</legend>
{{ form }}
<input type="text" placeholder="Write more about the route: about waypoints, points of interest and warnings.">
<input type="submit" value="Send route">
</form>
I have already tried to do everything as indicated in the Django Forms documentation. But still something is wrong. Even at the moment of starting the server, it writes an error:
cannot access local variable 'form' where it is not associated with a value
It is because you haven't defined form for GET method so:
def getAbout(request):
if request.method == 'POST':
form = RouteForm(request.POST)
if form.is_valid():
form.save()
return redirect('some_view_name_to_redirect')
else:
form=RouteForm()
return render(request, 'routes_form/form_page.html', {'form': form})
Note: Models in Django are written in singular form, as Django itself add s as the suffix, so it is better to name the models as City and Route.
Here you passed form = RouteForm(request.POST) object for POST request you need to pass for GET request so, when def getAbout(request) function called with GET request then renders it like this ...
def getAbout(request):
form=RouteForm() # <---- called at GET request
if request.method == 'POST':
form = RouteForm(request.POST) # <---- called at POST request
if form.is_valid():
form.save()
return redirect("/")
return render(request, 'routes_form/form_page.html', {'form': form})

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>

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

Django: posting a template value to a view

The Problem:
I'm tying to post to a view and pass on a value from the template by using a hidden value field and a submit button. The values from the submit button (ie the csrf_token) gets through but the hidden value does not. I've checked from the Wezkrug debugger that request.POST only contains form values and not my 'id' value from the hidden field.
Background:
The button takes you to a form where you can enter a comment. I'm trying to include the review.id that the user is commenting on to make commenting easy. I have the value as 'test' not for test purposes.
My form:
<div>
<form method='POST' action='/add_comment/'>
{% csrf_token %}
<input type="hidden" name='id' value='test'>
<input type="submit" value="Make a Comment">
</form>
</div>
Comment View:
#login_required
def make_comment(request):
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.user = request.user
comment.save()
# render?
return HttpResponseRedirect('/results/', {
'restaurant': get_object_or_404(
Restaurant,
name=request.POST['name'],
address=request.POST['address']
)
})
else:
form = CommentForm()
return render(request, 'stamped/comment.html', {'form': form})
Comment Model:
class Comment(models.Model):
content = models.TextField()
review = models.ForeignKey(Review)
user = models.ForeignKey(User)
date_added = models.DateTimeField(auto_now_add=True)
Comment ModelForm Code:
class CommentForm(ModelForm):
class Meta:
model = Comment
exclude = ('user', 'review',)
I've been trying to follow the tactics in this question, but using the request.session dict is undesirable because Id have to store an id for every review regardless if they're are ever commented on.
What is a more efficient way to pass variables from Template to View in Django?
Any ideas on how to include the hidden value in the POST? Thanks!
views.py
def make_comment(request):
if request.method == 'POST':
if 'prepair_comment' in request.POST:
review = get_object_or_404(Review, pk=request.POST.get('id'))
form = CommentForm({'review': review.id})
return render(request, 'stamped/comment.html', {
'form': form,
})
else: # save the comment
models.py
class CommentForm(ModelForm):
class Meta:
model = Comment
exclude = ('user',)
widgets = {'review': forms.HiddenInput()}
restaurant.html
<form method='POST' action='/add_comment/'>
{% csrf_token %}
<input type='hidden' value='{{ r.id }}' name='id'>
<input type="submit" name='prepair_comment' value="Make a Comment">
</form>
You can access the form with form.cleaned_data. You could also use a if form.is_valid() or if you want to ignore the hidden test value when there is no comment, then you could use a if/else logic to ignore the hidden value if comment is None: logic.
To access the form and only record the test value if comment is not None, the views.py might look like this:
def form_view(request):
if request.method == 'POST'
form = form(request.POST)
if form.is_valid():
comment = form.cleaned_data['comment']
# do something with other fields
if comment is not None:
id = form.cleaned_data['test']
# do something with the hidden 'id' test value from the form
return HttpResponseRedirect('/thanks/')
else:
form = form()
return render(request, 'form.html', {'form': form})
Here are the Django Docs that I would reference for this:
https://docs.djangoproject.com/en/dev/topics/forms/

How to save Django ModelForm data?

I have created form using ModelForm but its not saving data into database.
views.py
def answer(request):
if request.method == 'POST':
form = AnswerForm(request.POST)
if form.is_valid():
form.save()
else:
form = AnswerForm()
return render_to_response('quiz/index.html', {'form': form, })
template
<form action="." method="post">
{{ form.as_p }}
<input type="submit" value="Submit">
</form>
model
class Answer(models.Model):
answer = models.TextField()
class AnswerForm(ModelForm):
class Meta:
model = Answer
Where i was wrong ? :/
You forgot to handle the case where the form isn't valid.

Categories