changing CreateView behavior to preview data before save in django - django

I have gotten Creatview() class based function to work. When the submit succeeds, it has already the data and shows the 'success' page.
I'd like to change this behavior this way: When the CreateView() succeeds, I'd like the data to get validated, but not saved. Instead of going to the success page, I'd like to use the DetailView() class to display the newly created instance, so the user can see how it is going to look like when the data is eventually saved..
Once the user is happy with the data displayed, the user can click "save" in which case the data is saved and the CreateView() is completed or the user can click "re-edit", and go back to the form to change the data and then be shown the newly created instance using DetailView() (and repeat until the user is satisfied). What is the best way to do this using class based views elegantly?
from django.views.generic.edit import CreateView
from restaurant.models import Restaurant
from restaurant.forms import RestaurantForm
import uuid
class RestaurantCreate(CreateView):
form_class = RestaurantForm
template_name = 'restaurant_form.html'
model = Restaurant
def form_valid(self, form):
form.instance.created_by = self.request.user
form.instance.life_id = str(uuid.uuid1())
return super(RestaurantCreate, self).form_valid(form)
Also, I do know about Form wizard, but I do not have multiple page forms. Even if I ignore that, Form wizard's does not give the opportunity to preview data before the final save.
Edit: Related discussion on google groups, but no solutions

Here's what I should do:
Overwrite the form_valid method of the RestaurantCreate class and let the save the form in a session. From there you can redirect to another view , your RestaurentDetail view, there you would overwrite the get_object method by reading out the form out of the session and displaying what you need.
There I would also place a form with all fields hidden, except the submit/save button. The form will be populated by whatever was in your session. So when the user presses save a POST is done to another view RestaurantFinalCreate view for example. There you can just implement the CreateView as normal.
If you're uncertain which method to overwrite and how, take a look at: http://ccbv.co.uk/ it has been really helpful to me.
Also don't use super in the form_valid method of the RestaurantCreate view since that would trigger a save in the parent class ModelFormMixin.

Related

Django post form fields to another page

I have a Django form that takes filter options for a report. The report page is a separate view that renders the report based on the form data.
My first pass at this, I simply set the action of the form to the report page and method to GET. The form data was then passed directly the report view via the querystring which I would use GET to retrieve. The problem with this was that this bypassed form validation since the the form did not post back to its own view.
My next pass, I removed the form action (so it would post back to itself) and used form_valid (I am using class based views) to encode the form data and redirect to the report view like so:
ReportOptionsView(FormView)
form_class = OptionsForm
template_name = 'my_report_options.html'
report = reverse_lazy('my_report')
def form_valid(self, form):
qstr = urlencode(form.cleaned_data)
return redirect(self.report+"?"+qstr)
The report page works the same -I just retrieve the information from the querystring to filter the models and display the report.
I would prefer the form data not appear on the querystring of the report page. When I tried to redirect to the report page using a POST method is where I starting having trouble. Even going back to my original flow setting the form action to the report page (thus losing validation) and setting the form method to POST, I got 405 errors. I realize that there may be ways to do this using Javascript, but would prefer to stick with Django/Python
My question is, what is the proper method in Django to take cleaned data from a validated form and POST that data to separate view so that the form data is not exposed in the URL?

Django - Show history in admin working but only when actions take place in admin

In Django admin, when you are looking at a record there is a button called "history". When you click on this button, it tells you when the record was created and by whom and also each time a field was changed and by whom. I find this extremely useful. However, I noted that these only show up for actions that are done on the admin page. So when I change the record through a view, this is not displayed in that history. Is there an easy way to have my views store this information also so that it will all be visible from the admin page?
Thanks so much in advance for your help.
The admin app comes with a model - LogEntry. Every time you do something in the admin app, there is some code somewhere that saves a LogEntry. This is how the app works. For example in the changeform_view there is something like this:
def changeform_view(self, request, ...):
...
if request.method == "POST":
if all_valid(formsets) and form_validated:
# do some other stuff then
self.log_change(request, new_object, change_message)
def log_change(self, request, object, message):
"""
Log that an object has been successfully changed.
The default implementation creates an admin LogEntry object.
"""
from django.contrib.admin.models import CHANGE, LogEntry
return LogEntry.objects.log_action(
user_id=request.user.pk,
content_type_id=get_content_type_for_model(object).pk,
object_id=object.pk,
object_repr=str(object),
action_flag=CHANGE,
change_message=message,
)
LogEntry.objects.log_action is where the log is created. Unfortunately, this doesn't happen anywhere else, unless you were to make it happen.
There's nothing stopping you from doing this though. You can create a LogEntry wherever you want.
Having said that, it might be a bit confusing since when you see a LogEntry you now no longer no if that is a change that has happened because of someone manually changing some data via the admin app, or a change that has occurred programatically. It would probably be a better idea to create your own Log model, and save logs where and when you want.
You can always display your Logs in your in the relevant admin view should you so wish. Something like this will do the trick:
class MyAdmin(admin.modelAdmin):
readonly_fields = (logs_field,)
def logs_field(self, instance):
logs = Log.objects.filter(object=instance)
return format_html_join(
'\n', "<p>{}: {}</p>",
((log.date, log.message) for log in logs)
)

Django web application Taking user input and processing it

I am building a web application using django. I need to take a string input from the user and process it using a method I have written myself. How to achieve this in Django? Here are the things I need to do
Get User Input userinput = (string) On start page
Put this string as an argument in my method MyMethod(userinput) and Run it in the backend
Display what MyMethod() returns on another page.
I suggest that you start from django tutorial: https://docs.djangoproject.com/en/1.9/intro/tutorial01/
Basically, what you are going to need is form with one text field, HTML template that will render the form, view that will render HTML template with instance of a form when GET request arrives and call your MyMethod with value from form when POST request arrives and URL rule to call your view function on some URL.
Without additional data or any attempt to solve it and concrete problem you encounter - I can hardly offer more help.
You need to create a model with fields which you want to update by user input, then create a form based on this model. Then import this in a view and render it in a template
simple example:
forms.py:
class InputForm(forms.ModelForm):
class Meta:
model = YourModel
fields = ['fields_from_YourModel']
views.py:
from .forms import InputForm
def user_input(request):
input = CustomUser.objects.get(pk=request.user.pk)
if request.POST:
form = ProfileForm(request.POST, instance=input)
if form.is_valid:
form.save()
else:
form = ProfileForm()
return render(request, 'input.html', {'form':form})
Other steps more easier for beginner, you'll find examples in docs

Django wizardview: how to set up step data without validating the form

What I am trying to do I have a view which has a shortcut form which will ask a user to pre-fill some fields before a user is redirected to wizard forms.
For example:
class PreFillView():
def post(self,request):
# get the data from the form and save into request.session
# Then http redirect to the wizard view
Then from this view, I redirect it to a WizardView. In the wizard view, I catch all the information passed in from the previous view in dispatch function:
class MyWizardView(NamedUrlSessionWizardView):
def dispatch(self,request, *args, **kwargs):
#parse data from request.session
#set step data using these data
# Note these data fields only partially covered the form in the wizardview, there is still a couple of fields needed to be filled in the wizard view.
This almost works fine but the only problem is that it validates the form and pop up field error for the fields which are not pre-populated. I tried, if I only redirect to the wizard view without setting the step data, it is fine. It won't validate the form, so no field errors will be displayed.
I am pretty new to Django and not sure if I am doing the right thing and if yes, how can I avoid form to be validated after I set the step data for the current step? Any help will be appreciated.
Implement the WizardView.get_form_initial(step) method in you wizard view class.
This method gets step number as parameters and it should return dict for initial data for the form for that step.

Django: Form in base template

Hi Stackoverflow people,
In my Django project I created a form to register users. This forms can be called through a specific url -> view method. Once the user has filled in the form, presses submit, the same view method will be called and if form.is_valid() is true, then ... simply a standard form, nothing special.
Now, I would like to integrate this little form on every page, and therefore I would like to add it to the base template. I have read that I could populate the form variable through a context_processor, but could I define the process after the submission of the form?
I have created the context_processor.py (as below), added the context_processor to the TEMPLATE_CONTEXT_PROCESSOR dir in the settings (as described here):
from app.forms import Form
def registration_form(request):
return {
registration_form : Form()
}
First of all, the form variable won't be displayed.
And secondly, how do I manipulate the form submission?
I think I misunderstanding the context_processor of Django and would be more than happy about comments on the overall process.
Thank you!
how are you trying to access to form in your template? you probably don't want to use a function name as your dictionary key, maybe you want
return {
'registration_form': Form(),
}
not sure what you mean by manipulate the form submission, but i guess you'd need all the form processing logic in your context processor
if request.POST:
form = Form(request.POST)
# validate etc
instead of creating context processor, create template tag for the purpose and place the tag in base.html
for form submission and displaying errors use ajax, and front-end validations.