I am stuck with this error and I don't know what to do...
I followed the Django documentation here
I would like also to create a new Player object when I fill the empty extra form, but one requires field of the model must be based on request.user.team not seated directly by the user
Hope someone is familiar with ManagementForm
My files:
views.py
from django.shortcuts import render, redirect
from skeleton.models import Player
from django.contrib.auth.decorators import login_required
from .forms import PlayerForm
from django.forms import modelformset_factory
# Create your views here.
#login_required(login_url="/accounts/login/")
def team_area(request):
PlayerFormSet = modelformset_factory(Player, fields=('first_name', 'last_name'), extra=1)
if request.method == "POST":
player_formset = PlayerFormSet(
request.POST,
request.FILES,
queryset=Player.objects.all().filter(team=request.user.team),)
if player_formset.is_valid():
player_formset.save()
return redirect('team_area:home')
else:
player_formset = PlayerFormSet(queryset=Player.objects.all().filter(team=request.user.team))
return render(request, 'team_area/team_area.html', {'player_formset': player_formset})
team_area.html
{% extends 'base_layout.html' %}
{% block content %}
<h1>Area Squadra</h1>
<form method="post" action="">
{% csrf_token %}
{{ formset.management_form }}
{% for player_form in player_formset %}
{% for field in player_form %}
{{ field.label_tag }} {{ field }}
{% endfor %}
<br>
{% endfor %}
<input type="submit" value="Aggiorna">
</form>
{% endblock %}
A formset may contain more then a single form, so for saving the data from a formset in the view file, you have to loop through all the forms and save each form's data. Like in your views.py file you can write:
if player_formset.is_valid():
for form in player_formset:
form.save()
This will create as many new objects of Player as there are new forms in the formset (assuming you have not deleted any form or edited the pre-existing form).
One must also update the Management Form data in the .html file as soon as the user clicks on Add Player button
This is the solution I found and used using
.save(commit=False)
if request.method == "POST":
player_formset = PlayerFormSet(request.POST, request.FILES, queryset=Player.objects.all().filter(team=request.user.team),)
for player_form in player_formset:
if player_form.is_valid():
player = player_form.save(commit=False)
player.team = request.user.team
if player_formset.is_valid():
player_formset.save()
Related
Sure I've missed something obvious, but any help appreciated.
I have a form model:
class UserForm(forms.Form):
name = forms.CharField()
A view:
def userform(req):
context = {}
context['user_form'] = UserForm()
context['message'] = 'test message'
return render(req, 'apps/userform.html', context)
And a template:
{% extends 'base.html' %}
{% block title %} | User Form {% endblock %}
{% block content %}
<h1>Form page</h1>
<form method='POST'>
{% csrf_token %}
{{ user_form }}
<button type='submit'>Send</button>
</form>
{{ message }}
{% endblock %}
I'm pretty sure everything is connected correctly and imported as required - the 'message' property on context renders fine under the form.
However, {{ user_form }} in the template renders the actual Form object instance, rather than the actual form field I'm expecting. I see:
<userform.views.UserForm object at 0x7fcab17e5c10>
Then the form submit button.
What have I missed?
Django 4, if that matters.
So the issue was I had a class based view in the views file with the same name as my Form class - I guess that was getting instantiated, rather than the Form class. Commented out the CBV and everything worked.
If I'd looked harder at the error message, I would have probably seen this sooner as the instantiated object is clearly in the views folder, rather than the forms one...
im making a signup page in a django project using the UserCreationForm but when rendering my html i only see the submit button
from django.shortcuts import render
from django.contrib.auth.forms import UserCreationForm
def register(request):
form = UserCreationForm
return(render(request, 'register.html', {form: form}))
{% extends 'base.html' %}
{% block title %}Sign Up{% endblock %}
{% block body %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="button">
<button type="submit">Sign up</button>
</form>
{% endblock %}
You can not use the form as key of the context, you should use 'form'. Furthermore it is not a good idea to pass a reference to the class, you should create an instance of the form in the view, so:
from django.shortcuts import render
from django.contrib.auth.forms import UserCreationForm
def register(request):
form = UserCreationForm()
# use 'form' instead of form ↓ ↓
return render(request, 'register.html', {'form': form})
If you had used a form object, instead of a reference to the class, it would have raised an error that a Form is not hashable. But since you used a reference to the form class, there was no error, and thus this remained undetected.
The problem is within the django views function..Use below code instead..
you should pass it as a string variable {'form' :form}
return render(request, 'register.html', {'form': form})
When filling out a form I get "This field is required." even though all fields are filled in.
It doesn't have to do with setting required to False or anything like that, because all fields are required.
views.py
def upload(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
title = form.cleaned_data['title']
username = request.user.get_username()
category = form.cleaned_data['category']
handle_uploaded_file(request.FILES['file'],title,username,category)
return HttpResponseRedirect('')
else:
form = UploadFileForm()
return render(request, 'main/upload.html', {'form': form})
function
def handle_uploaded_file(f,title,username,category):
with open('/uploads/' + category + '/' + title, 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
forms.py
class UploadFileForm(forms.Form):
title = forms.CharField(max_length=50)
category = forms.CharField(max_length=50)
file = forms.FileField()
upload.html
{% extends 'base.html' %}
{% block title %}Upload{% endblock %}
{% block content %}
{% if user.is_authenticated %}
Uploading as: {{ user.username }}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit"/>
</form>
{% else %}
<p>You are not logged in</p>
login
{% endif %}
{% endblock %}
The error I get when filling out a form is: "This field is required"
Screenshot:
When I select a file and it throws the error it unselects whatever file I've selected, similar to how the password field is cleared when hitting sign up without completing every field.
The file isn't being submitted with the request because you didn't sent the correct enctype on the form element. Here are Django's docs concerning that.
<form method="post" enctype="multipart/form-data">
One way to verify this/debug it would be to print the form's data form.data, request.POST and/or request.FILES before the call to is_valid. Or verifying the request in a browser's dev tools.
So, a total Django Model Formset Newb question. I'm trying to save my form and keep getting this error:
['ManagementForm data is missing or has been tampered with']
Here is what I have for my TemplateView:
class AttendanceTemplate(TemplateView):
template_name = 'attendance/index.html'
def get_context_data(self, **kwargs):
context = super(AttendanceTemplate, self).get_context_data(**kwargs)
instruction = Instruction(self.request.user.username)
sections_list = self.request.GET.getlist('sections_list')
term = self.request.GET.get('term', instruction.term)
enrollments = Enrollment.objects.using('wisp').prefetch_related('profile').filter(section_id__in=['111111'], term=term)
attendanceQuery = Enrollment.objects.using('wisp').prefetch_related('student').filter(section_id__in=['111111'], term=term)
for enrollment in attendanceQuery:
attendance, created = Attendance.objects.update_or_create(
section_id=enrollment.section_id,
term=enrollment.term,
first_name=enrollment.student.first_name,
last_name=enrollment.student.last_name,
email_address=enrollment.student.email_address,
)
something = Attendance.objects.filter(section_id__in=['111111'], term=term)
formset = AttendanceFormSet(queryset=something)
combined = zip(enrollments, formset)
context['combined'] = combined
return context
Here is how I'm trying to save the form:
def post(self, request):
formset = AttendanceFormSet(request.POST)
if formset.is_valid():
for thing in formset:
formset = thing.save()
return render_to_response("template/index.html",{'formset': formset}, RequestContext(request))
else:
return HttpResponse(error.msg)
Here is what I have in my template:
<form method="POST" action="">
{% csrf_token %}
{% for enrollment, form in combined %}
<div class="wrapper-formset">
<div>
{{ form.first_name.value }}
{{ form.last_name.value }}
{{ form.email_address.value }}
</div>
<div class="clear-all"></div>
</div>
{% endfor %}
<button type="submit" class="save btn btn-default">Save</button>
</form>
Am I saving my form wrong? Maybe my loop is wrong? Also, I'd prefer to print each field out individually, so using the "myform.management_Form" may not work for me? (e.g., myform.management_form.field_name)
If you render the forms separately, then you must include the management form in your template. The fact that you are zipping your forms makes no difference.
Including the management form is easy, just add {% formset.management_form %} to your template.
<form method="POST" action="">
{% csrf_token %}
{{ formset.management_form }}
{% for enrollment, form in combined %}
...
For that to work, you'll need to make sure that formset is in the template context, for example:
context['formset'] = formset
You might find the docs on using model formsets in the template useful. It would be a good idea to start with the simplest option, {{ formset }}, test it, then gradually customize the template. That makes it easier to debug when stuff goes wrong. At the moment it looks like you have missed out {{ form.id }}.
I am trying to do a basic search feature but I am having a small issue. When I go to the template that has the search form, it is displaying all the items before I even try to search. Is there a way to show a blank template until the user has put in a search term and hit the search button?
Example:
[Search field][Button]
1
2
3
etc
views.py
def view_player_home(request):
if request.method == 'GET':
form = searchPlayerForm(request.GET)
if form.is_valid():
string = form.cleaned_data.get('text')
players = Player.objects.filter(Q(first_name__icontains = string)|Q(last_name__icontains = string))
return render_to_response('player/player.html', {'form': form, 'players':players}, context_instance=RequestContext(request))
else:
form = searchPlayerForm()
return render_to_response('player/player.html', {'form': form}, context_instance=RequestContext(request))
forms.py
class searchPlayerForm(forms.Form):
text = forms.CharField(label = "Search")
def __init__(self, *args, **kwargs):
super(searchPlayerForm, self).__init__(*args, **kwargs)
self.fields['text'].required = False
template
{% extends "base.html" %}
{% block content %}
<h5>Find Player</h5>
<form method="GET" action="">
{% csrf_token %}
{{ form.as_table }}
<input type="submit" value="Submit"/>
</form>
{% if players %}
{% for p in players %}
{{ p.first_name }} {{ p.last_name }}
{% endfor %}
{% else %}
No Players
{% endif %}
{% endblock %}
One change should do it:
if request.method == 'GET':
should be
if request.GET:
The underlying issue is that your request method is always GET, so you never go into the else block or to the bottom of the function.
Another option is to explicitly look for a term in the GET data
if request.GET and 'text' in request.GET:
# do query / processing
or even don't allow blanks
if request.GET and 'text' in request.GET and request.GET['text'] != '':
# do query / processing
This work easily if you only have one field or are checking if options in a form have certain values.
When doing a lot of fields, I like to do a named submit button so that I can check is it's been hit, and then do the if statements checking for the button name.