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/
Related
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>
Python noob here trying to learn something very simple.
I'm trying to create a basic form that takes some personal information from a user and saves it into a sqlite3 table with the username of the user as the primary key.
My models.py looks like this:
class userinfo(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, primary_key= True,
on_delete=models.CASCADE)
name = models.CharField(max_length = 200, blank = True)
email = models.EmailField(max_length= 300, default = 'Null')
phone = models.CharField(max_length= 10, default = 'Null')
def __unicode__(self):
return self.user
forms.py:
class NewList(forms.ModelForm):
class Meta:
model = userinfo
exclude = {'user'}
views.py
def newlist(request):
if request.method == 'POST':
form = NewList(request.POST)
if form.is_valid():
Event = form.save(commit = False)
Event.save()
return redirect('/home')
else:
form = NewList()
return render(request, 'home/newlist.html', {'form': form})
html:
{% load static %}
<form action="/home/" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit">
</form>
urls.py too, but I don't know how that would help:
urlpatterns = [
url(r'^newlist/$', views.newlist, name='newlist')
]
So when I go to the url, I see the form. I can then fill the form, but when I submit the form, the data doesn't go into the database.
What am I doing wrong here?
Thanks in advance!
I think all you need to do is just save the form if it's valid, probably also add the userinfo as an instance of the form. You are also exluding the user from the form and need to assign it manually.
def newlist(request):
if request.user.is_authenticated():
user = request.user
if request.method == 'POST':
form = NewList(request.POST, instance=user.userinfo)
if form.is_valid():
form.save(commit=false)
form.user = user
form.save()
return redirect('/home')
else:
form = NewList(instance=user.userinfo) # add this if you want it to automatically fill the form with the old data if there is any.
return render(request, 'home/newlist.html', {'form': form})
The rest look like it should work.Except you need to send the post URL back to newlist:
{% load static %}
<form action="/newlist/" method="POST">
{% csrf_token %}
{{ form.as_p }}
</form>
If users are assigned at the creation of the model the first time, you don't need the user save, but since this is saving a users data you want to make sure they are logged in anyway:
def newlist(request):
if request.user.is_authenticated():
user = request.user
if request.method == 'POST':
form = NewList(request.POST, instance=user.userinfo)
if form.is_valid():
form.save()
return redirect('/home')
else:
form = NewList(instance=user.userinfo) # add this if you want it to automatically fill the form with the old data if there is any.
return render(request, 'home/newlist.html', {'form': form})
The instance is the model it is either going to save to, or copying data from. In the: form = NewList(request.POST, instance=user.userinfo) part, it is taking the POST data from the form, and linking that to the specific model entry of user.userinfo, however, it will only save to the database when you call form.save().
The user.userinfo is just so you can get the correct form to save to, as userinfo is a onetoone model to user. Thus making it possible to get it with user.userinfo.
The form = NewList(instance=user.userinfo) part is where it takes the currently logged in user's userinfo and copies into the form before it is rendered, so the old userinfo data will be prefilled into the form in the html. That being if it got the correct userinfo model.
I'm new to Django
In my homepage, I want to give 2 choices to users: to upload photos to a new album, or to an existing one.
The problem is one of the forms is initially not shown in the HTML,I can only see its submit button. But when I click on the submit button, then the form appears, along with the 'This field is required' warnings.
For this I have created 2 forms in forms.py
class AlbumForm(ModelForm):
class Meta:
model = Album
fields = ('title', 'description',)
class dropDownForm(forms.Form):
Albums = forms.ModelChoiceField(queryset=Album.objects.filter(user__id=1))
def __init__(self, user, *args, **kwargs):
super(dropDownForm, self).__init__(*args, **kwargs)
self.fields['Albums'].queryset = Album.objects.filter(user__id=user.id)
AlbumForm is for creating a new album, dropDownForm is for choosing from an existing one.
In views.py I have:
def upload_album(request):
if request.user.is_authenticated():
if request.user.albums.all() is not None:
albums = request.user.albums.all()
dropdownAlbum = request.POST.get('Albums')
if request.method == 'GET':
album = AlbumForm()
form = dropDownForm(request.user)
if ((request.method == 'POST') and ('ExistingAlbum' in request.POST)):
form = dropDownForm(request.user)
userID = request.user.id
curr = UserProfile.objects.filter(id=userID).first()
curr.currentAlbum = int(dropdownAlbum)
intAlbum = int(dropdownAlbum)
curr.save()
return HttpResponseRedirect('/upload-media')
if ((request.method == 'POST') and ('CreateNewAlbum' in request.POST)):
form2 = AlbumForm(request.POST)
if form2.is_valid():
album = form2.save(commit=False)
album.user = request.user
album = form2.save()
created_album_id = Album.objects.filter(title=album).first().id
userID = request.user.id
curr = UserProfile.objects.filter(id=userID).first()
curr.currentAlbum = created_album_id
curr.save()
request.user.albums.add(album)
return HttpResponseRedirect('/upload-media/')
return render(request, "base.html", locals())
and in HTML:
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" name="ExistingAlbum" value="Continue" href="/upload-media/">
</form>
</div>
<div>
<form method="POST">
{% csrf_token %}
{{ form2.as_p }}
<button type="submit" name="CreateNewAlbum" value="Create New Album">Create</button>
</form>
</div>
Any help is appreciated.
I've just looked up what locals actually is and that is a horrible way of constructing your context data (which is why I'm not surprised I haven't ever heard of it).
Your context data should be a dictionary made up of those values that you need in order for your template to render correctly. Therefore you should construct a dictionary that includes the elements that you need.
As a starting point that would be.
{
'form': AlbumForm(),
'form2': dropDownForm(request.user)
}
My guess is form2 does not appear.
The problem is: when you initially request the page it's a GET request, therefore only the following part is executed:
if request.method == 'GET':
album = AlbumForm()
form = dropDownForm(request.user)
return render(request, "base.html", locals())
Because other if branches require POST, which is a request verb used when submitting the data, which occurs when you press the Submit button.
When you call locals() the context is filled with album and form, but not form2, because it's not initialized in local scope in this case. You need to add form2 initialization to the above part, e.g.:
if request.method == 'GET':
form2 = AlbumForm()
form = dropDownForm(request.user)
...
return render(request, "base.html", locals())
P.S. Using locals() to fill a context is smart, but bad idea - it's insecure, it adds ALL the variables defined in the local scope to the context available in template.
I am getting a valid response back when requesting my form, but I am getting no form fields with the response. It is loading the Submit button only, but no form fields.
Goal: get form fields to load and be able to submit form.
I have a views.py:
def Registration(request):
form = NewUserRegistrationForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
form.save()
return HttpResponseRedirect("/Login/")
else:
form = NewUserRegistrationForm()
return render(request, 'VA/reuse/register.html', {
'form': form
})
forms.py
class NewUserRegistrationForm(UserCreationForm):
username = forms.CharField(required=True,max_length=30,validators=[RegexValidator('^[A-Za-z0-9]{1,30}$','e.g. must be 30 characters or less','Invalid Entry')])
email = forms.EmailField(required=True, max_length=75)
password = forms.PasswordInput()
class Meta:
model = User
fields = ("username", "email", "password1","password2")
def save(self, commit=True):
user = super(NewUserRegistrationForm, self).save(commit=False)
user.username = self.cleaned_data["username"]
user.email = self.cleaned_data["email"]
user.password = self.cleaned_data["password1"]
if commit:
user.save()
return user
a template
<div id="register_bubble">
<form method="post" id="userRegistration">
{% csrf_token %}
{{ NewUserRegForm.as_p }}
<input type="submit" value="Submit" />
</form> <!-- /RegistrationForm (FORM) -->
</div>
What am I doing wrong here? I'm getting no error while in debug mode locally either.
Thank you!
You have two mistakes.
Firstly, you're passing the form class into the template context, not the form instance: the class is NewUserRegistrationForm, but you've instantiated it as NewUserRegForm, and that's what you should be passing as the value in the form context.
To make it more complicated, the key name you've given to that value is also NewUserRegistrationForm - but you're still referring to NewUserRegForm in the template, even though that doesn't exist there.
This would be much more obvious if you used PEP8 compliant names. Instances should be lower case with underscore: eg new_user_registration_form. However, in this case you could just call it form, since there's only one.
return render(request, 'mysite/reuse/register.html', {
'NewUserRegForm': NewUserRegForm
})
or, better:
form = NewUserRegistrationForm(request.POST or None)
...
return render(request, 'mysite/reuse/register.html', {
'form': form
})
You're passing the form instance to the context as 'form', but calling it in the template as {{ NewUserRegForm.as_p }}.
You should use {{ form.as_p }} instead.
I am new to django, and have been tying to pass a User object to a ModelForm and then validate it. That is adding the User object as a ForeignKey to a Note object in the end, where the ModelForm is a Meta of the class Note.
My forms.py:
class NoteForm(ModelForm):
class Meta:
model = Note
My views.py:
def addNote(request):
if request.method == 'POST':
user = User.objects.get(username=request.POST['user'])
model_form = NoteForm(request.POST, request.FILES, user)
if model_form.is_valid():
model_form.save()
return HttpResponseRedirect(reverse('index'))
return HttpResponse('De indtastede data er ikke gyldige')
return render(request, 'studies/uploadfile.html')
My template.html:
<form enctype="multipart/form-data" method="post" action="/notes/add/">
Note Title: <input type="text" name="name" /> <br />
Select Note: <input type="file" name="note" /> <br />
<input type="hidden" name="user" value="{{ user.id }}">
<input type="submit" value="submit" />
{% csrf_token %}
</form>
I have tried using the request.user, since im trying to get the current user logged on and adding that user as the ForreignKey.
Any help will be appreciated, beforehand thanks.
I'm not sure what the point is of wanting to send it to the template. You have it in the view both before and after validation, after all: better to deal with it there.
The thing to do is to exclude the user field from the form definition, then set it manually on save:
class NoteForm(ModelForm):
class Meta:
model = Note
exclude = ('user',)
if request.method == 'POST':
model_form = NoteForm(request.POST, request.FILES)
if model_form.is_valid():
note = model_form.save(commit=True)
note.user = request.user
note.save()
return...
Also note that your view never sends any validation errors to the template, and your template doesn't show errors or the invalid values that the user has entered. Please follow the structure set out in the documentation.
You can extend the save method of the form,
def save(self, user):
note = super(NoteForm, self)
note.user = user
note.save()
return note
Also your view must be in this structure:
from django.shortcuts import render
from django.http import HttpResponseRedirect
def contact(request):
if request.method == 'POST': # If the form has been submitted...
form = ContactForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
# note: NoteForm.save(request.user)
return HttpResponseRedirect('/thanks/') # Redirect after POST
else:
form = ContactForm() # An unbound form
return render(request, 'contact.html', {
'form': form,
})
(copied from https://docs.djangoproject.com/en/dev/topics/forms/)
Look here https://docs.djangoproject.com/en/1.2/ref/templates/api/#subclassing-context-requestcontext