Good afternoon,
I have a simple Django 2.2 application for users to check in equipment they have checked out. A table of users and items they have checked out dominates the top of the page. On the very bottom row, a single text/submit form. I would like this to happen:
user enters equipment id and submits
page re-displays with: name removed from table (if success), form cleared, success/fail message next to cleared form.
I am close. All of my logic and queries work, my item gets checked back in. However, the page re-renders with no table of users, just the form with the old data still in it.
views.py
class EquipmentReturn(View):
def get(self, request, *args, **kwargs):
# get checked out items for display table -this works
form = ExpressCheckInForm(request.POST)
return render(request, 'eq_return.html',
context={'master_table': master_table,
'form': form}
def post(self, request):
if request.method == 'POST'
form = ExpressCheckInForm(request.POST)
if form.is_valid():
# this checks the item back in (or not) and creates messages-works
else:
form - ExpressCheckInForm()
return render(request, 'eq_return.html', context={'form': form}
I know there is a better way to do this. For instance, my form would not appear until I declared it in the get function. How can I make all of this happen on one page? Thanks!
I think something like this might work. I assume that there is missing code here, for example where you get the master_table.
class EquipmentReturn(View):
def get(self, request, *args, **kwargs):
# get checked out items for display table -this works
form = ExpressCheckInForm()
return render(
request, 'eq_return.html',
context={'master_table': master_table, 'form': form},
)
def post(self, request):
form = ExpressCheckInForm(request.POST)
if form.is_valid():
# this checks the item back in (or not) and creates messages-works
# after saving the form or whatever you want, you just need to redirect back
# to your url. It will call get again and start over
return HttpResonseRedirect(reverse('your-url-name'))
return render(request, 'eq_return.html', context={'form': form})
It looks like you are still in the function based view mindset. Search differences and how to understand and use class based views.
Related
Good evening, I am trying to get the id of my model Note that is sent by means of a form, but when I put form.id it tells me that id is not defined, try to get it through the user session but it says that it was not found.
def add_book(request):
template_name = 'books/create_note.html'
book = get_or_create_book(request)
form = NoteForm(request.POST)
if request.method == 'POST' and form.is_valid():
note = Note.objects.get(pk=form.pk)
book.notes.add(note)
form.save()
return redirect('books:book')
return render(request, template_name, {
'form': form,
})
and this is the form
class NoteForm(ModelForm):
class Meta:
model = Note
fields = (
'title', 'nota'
)
labels = {
'title': 'Titulo',
'nota': 'Nota',
}
try creating an instance of my Note model but when it comes time to create it tells me it is empty.
I'm new to Django, but I had similar problems that frustrate me. not sure if I have the hang of it yet, but I think what might be happening is that when you first go to the page there is a GET request, so your if statement misses it. It then it reaches the last line and goes to template_name without the form being assigned so the form never gets a Post requests. In the terminal you can see the POST and GET requests. I ended up also printing out request.method a lot before and after if statements just to help trace what was going on.
else:
form=NoteForm()
Then your return render(request,....
making sure it goes back to the correct html page.
The thing that worked for me eventually was something like
def Search_Page(request):
if request.method=='POST':
form = Search_Page_Form(request.POST)
if form.is_valid():
do some stuff and save the change to the model
return(redirect('mainapp:Evaluate_Page'))
else:
form=Search_Page_Form()
return render(request, 'mainapp/Search_Page.html', {'form': form})
views.py
from forms.py import PersonCreateForm
class PersonCreateView(CreateView):
model = Person
form_class = PersonCreateForm
template_name = "my_app/create_person.html"
def form_valid(self, form):
self.object = form.save()
return redirect('/homepage/')
class PeopleListView(ListView):
[...]
context.update({
'task_form': TaskCreateForm(),
return context
In my template I just add in action url which handle PersonCreateView.
<form action="{% url 'people_create' %}" method="post">{% csrf_token %}
When Form is valid then all data are saved without problems and it redirects me to '/homepage/.
But when my form is invalid then it redirects me to to {% url 'people_create' %} and shows errors at /homepage/people_create/
How can I avoid that? I want all errors show at same page without redirect.
Handle the form on the same view you build it, otherwise the page will change. You may mix django.views.generic.edit.ModelFormMixin into your PeopleListView so it has most of the features you need.
class PeopleListView(ModelFormMixin, ListView):
success_url = '/homepage/' # should use reverse() here
def get_context_data(self, **kwargs):
# only add the form if it is not already given to us
if not 'task_form' in kwargs:
kwargs['task_form'] = self.get_form()
return super(PeopleListView, self).get_context_data(**kwargs)
def post(self, request, *args, **kwargs):
# ListView won't have a post method, we define one
form = self.get_form()
if form.is_valid():
return self.form_valid(form) # default behavior will save and redirect
else:
return self.form_invalid(form) # default behavior has to be overridden (see below)
def form_invalid(self, form):
# Whatever you wanna do. This example simply reloads the list
self.object_list = self.get_queryset()
context = self.get_context_data(task_form=form)
return self.render_to_response(context)
There, you have three code paths:
Initial display will load the listview as usual, only an empty form will be added to the context.
On submitting valid input, the form_valid method is invoked, which will redirect to /homepage/.
On submitting invalid input, our overridden form_invalid method is invoked, which will render the page normally, except the form will contain the validation errors.
You may make the whole thing a bit more staightforward using a cached property for the form, but then you'd start working against Django's shipped views instead of with it, and might as well just use the basic View class and implement all logic by yourself. I'd stick with Django's views, but ymmv.
I am creating a series of forms, processed via Django's form wizard, however, the forms consist of many dropdown boxes, the content of which depend on the current user and therefore, I need to pass the User as a kewword argument.
What I have at the moment is this:
class ViewDataWizard(SessionWizardView):
template_name="wizards/data/view_data.html"
def done(self, form_list,**kwargs):
form_data = process_form_data(form_list)
return render_to_response('wizards/data/view_data_done.html',{'form_data':form_data})
However, I am seeking to produce this:
class ViewDataWizard(SessionWizardView):
template_name="wizards/data/view_data.html"
def get_form_kwargs(self, step):
if step == 0:
return {'user':<USEROBJECT>}
else:
return {}
def done(self, form_list,**kwargs):
form_data = process_form_data(form_list)
return render_to_response('wizards/data/view_data_done.html',{'form_data':form_data})
Where in the second example above, I need to substitute USEROBJECT with the current user, to seed the series of forms.
Am I missing something really obvious? Traditionally I would get user from request.user in a given view, however, this seems elusive in the forms wizard process...
You can get the request object from self.
def get_form_kwargs(self, step):
if step == 0:
return {'user': self.request.user}
else:
return {}
I have a django form I'm attempting to add CAPTCHA support to. However, this requires me to pass request.session to the form. To accomplish that, I added this constructor to the form:
def __init__(self, request=None, *args, **kwargs):
super(RegistrationForm, self).__init__(*args, **kwargs)
self.request = request
I then instantiate the RegistrationForm by passing the request object to it. However, when submitting the form, it fails to clean any of the fields. It just fails validation and passes a blank field back to the template. Here is the registration code that fails:
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
...do registration...
else:
return render(request, 'template.htm', {'form': form})
No matter what I put in the fields, it never validates. In fact, it doesn't even look like it cleans the fields. I just get back a new blank form after hitting the register button, no errors, nothing.
Any ideas?
Based on the code you posted, it looks as though you are passing request.POST into the request parameter for your RegistrationForm. i.e. you are doing the equivalent of:
form = RegistrationForm(request=request.POST)
What you really want to do is this:
form = RegistrationForm(request=request, data=request.POST)
Try this and see if it works for you.
Is it possible to build a two-stage form for creating an object in Django admin?
When an admin user visits /admin/my-app/article/add/, I'd like to display some options. Then, the app would display the creation page with pre-calculated fields based on the selections made.
You could overwrite the add_view method on the ModelAdmin (Source) of myapp.article. It is responsible for rendering the modelform and adding objects to the database.
While adding your functionality, you likely want to keep the original code intact instead of copying/modifying it.
Draft
def add_view(self, request, **kwargs):
if Stage1:
do_my_stuff()
return response
else:
return super(ModelAdmin, self).add_view(self, request, **kwargs)
Now you need to distinguish between the two stages. A parameter in the GET query string could do that. To pass initial data to a form in the admin, you only need to include the fieldname value pairs as parameters in the querystring.
Draft 2
def add_view(self, request, **kwargs):
if 'stage2' not in request.GET:
if request.method == 'POST':
# calculate values
parameters = 'field1=foo&field2=bar'
return redirect('myapp_article_add' + '?stage2=1&' + parameters)
else:
# prepare form for selections
return response
else:
return super(ModelAdmin, self).add_view(self, request, **kwargs)
You probably need to look at the code to return a correct response in your first stage. There are a couple of template variables add_view sets, but hopefully this is a good start to look further.