Get form-data for Django tests - django

I would like to test a Django form, without spelling out myself all the POSTed data that would normally go into it.
In a real application, this data would be provided by the browser, based on the form as rendered (as HTML) by Django.
How do I get the data without going through the browser?
form0 = MyForm(instance=obj) # form which would be shown in normal usage
data = the_magic_function(form0) # data which would be posted if user just pressed submit right away
# potentially manipulate some parts of this data to make the test interesting
form1 = MyForm(instance=obj, data=data)
# actual tests are on form1
form.initial is kinda what I'm looking for, but not quite: it contains Python objects rather than strings.

Related

How to make filtering non model data in flask-admin

I have to make dashboard like view in flask-admin that will use data retrieved from external API. I have already written a functions that get date ranges and return data from that range. I should use BaseView probably but I don't know how to actually write it to make filters work. This is example function that i have to use: charts = generate_data_for_dashboard('164', '6423FACA-FC71-489D-BF32-3A671AB747E3', '2018-03-01', '2018-09-01'). Those params should be chosen from 3 different dropdowns. So far I know only how to render views with pre coded data like this :
class DashboardView(BaseView):
kwargs = {}
#expose('/', methods=('GET',))
def statistics_charts(self):
user = current_user
company = g.company
offices = Office.query.filter_by(company_id=company.id)
self.kwargs['user'] = user
self.kwargs['company'] = company
charts = generate_data_for_dashboard('164', '6423FACA-FC71-489D-BF32-3A671AB747E3', '2018-03-01', '2018-09-01')
self.kwargs['chart1'] = charts[0]
self.kwargs['chart2'] = charts[1]
return self.render('stats/dashboard.html', **self.kwargs)
But I need some kind of form to filter it. In addition date filter dropdown should have dynamic options : current_week, last_week, current_month, last_month, last_year. Don't know where to start.
You should use WTForms to build a form. You then have to decide if you want the data to be fetched on Submit or without a reload of the page. In the former case, you can just return the fetched information on the response page in your statistics_charts view. But if you want the data to update without a reload, you'll need to use JavaScript to track the form field changes, send the AJAX request to the API, and then interpret the resulting JSON and update your dashboard graphs and tables as needed.
I have not used it, but this tutorial says you can use Dash for substantial parts of this task, while mostly writing in Python. So that could be something to check out. There is also flask_jsondash which might work for you.

Django function execution

In views, I have a function defined which is executed when the user submits the form online. After the form submission there are some database transactions that I perform and then based on the existing data in the database API's are triggered:
triggerapi():
execute API to send Email to the user and the administrator about
the submitted form
def databasetransactions():
check the data in the submitted form with the data in DB
if the last data submitted by the user is before 10 mins or more:
triggerapi()
def formsubmitted(request):
save the user input in variables
Databasetransactions()
save the data from the submitted form in the DB
In the above case, the user clicks on submit button 2 times in less than 5 milliseond duration. So 2 parallel data starts to process and both trigger Email which is not the desired behavior.
Is there a way to avoid this ? So that for a user session, the application should only accept the data once all the older data processing is completed ?
Since we are talking in pseudo-code, one way could be to use a singleton pattern for triggerapi() and return Not Allowed in case it is already istantiated.
There are multiple ways to solve this issue.
One of them would be to create a new session variable
request.session['activetransaction'] = True
This would however require you to pass request, unless it is already passed and we got a changed code portion. You can also add an instance/ class flag for it in the same way and check with it.
Another way, which might work if you need those submissions handled after the previous one, you can always add a while request.session['activetransaction']: and do the handling afterwards.
def formsubmitted(request):
if 'activetransaction' not in request.session or not request.session['activetransaction']:
request.session['activetransaction'] = True
# save the user input in variables
Databasetransactions()
# save the data from the submitted form in the DB
request.session['activetransaction'] = False
...

How to send JSON data with form data using Flask

I'm making a system to track entries to a sports day event and I can get the data from the form to the Python back-end but I don't know how to get the data for the event entries to the back-end too.
I have a form I've already created using Flask and WTForms and I can submit all the data relating to the user but since they can enter from just a single event all the way up to every event they are able to enter the form will have a variable number of selection fields, I want to pack this data from the selection fields into a JSON string and then have Python process it since that is very easy. My only problem is, how can I get this data into a JSON string then send it in a single request to the back-end with the other data, like first name, last name etc.
Screenshot showing the user interface of the form
from flask import jsonify
#app.route('/selects')
def selects():
selects = ['one', 'two']
return jsonify(selects)
I have the same question and found answer in this tutorial. If you already use WTForm to make the form, the content can be access via methods. This should be straightforward. https://pythonspot.com/category/pro/web/page/2/

Sharing data between two views through template in Django?

I may have overcomplicated things.
I have two views. The first view generates a bunch of temporary data based on the user's input from the form. Each of the generated data contains a name and misc data. I want to pass only the names to the template to be rendered as a list of hyperlinks. If the user clicks on one of them, the second view should be given the specific name the user clicked on so that the view can manipulate it. The only problem is, I don't know how to get the misc data associated with the name.
The misc data generated could contain random characters that's not a standard character in URLs, so I can't turn misc into a hyperlink like I can with just the name.
I have something like this:
views:
# Displays the temp data names
def display(request):
return render_to_response('display.html',{},context_instance=RequestContext(request))
# User provides input, generate temp data to be displayed as hyperlinks
def search(request):
form = SearchForm(request.POST)
if form.is_valid():
usr_input = form.cleaned_data['input']
data = generate_data(usr_input) # generates a list of (name, misc) data.
request.session['hyperlinks'] = get_list_names(data) # returns only names in data
return HttpResponseRedirect('views.display')
else:
....
# User has clicked on a hyperlink, we must process specific data given its name.
def process_data(request, name):
# How to get associated misc data created from search()?
I haven't written the template yet, but the idea is:
template:
{% for name_link in request.session.hyperlinks %}
<a href={% url process name_link %}>
{% endfor %}
One solution could be creating a bunch of session variables:
for name in get_list_names(data):
request.session[name] = // associated misc data
But this seems like a waste. Plus I'd have to manage deleting the session variable later on since this is only temporary data generated based on user input. A new input from the user would create another huge horde of session variables!
Another solution could be to store it temporarily in the database, but that also seems like a bad idea.
EDIT - Trying out suggestion by christophe31:
I'm not quite sure if I understand your suggestion, but is it something like this?
data_dict = {name1:misc1, name2:misc2, etc...}
encoded = urllib.urlencode(data_dict) # encoded = 'name1=misc1&name2:misc2...etc'
request.session['hyperlinks'] = encoded
A few questions on this though:
1) Wouldn't encoding it using urllib defeat the purpose of having a dictionary? It returns a string rather than a dictionary
2) To expand on (1), what if the misc data had '&' and '=' in it? It would screw up parsing which is the key and value by the second view. Also, misc data may have unusual characters, so allowing that to be part of the url to be displayed may be bad.
3) Does Django protect from allowing the user to maliciously modify the session misc data so that the misc data generated from the first view may be different than the one passed to the second view? That would be a problem!
You may want to put a dictionary as a session variable, set a cookie, or pass as get argument throught the link your data.
For me you have to put all these data in a dictionary before export it as get parameters (with urllib2) or store it in your user's session.
Ask me if you want more info on a suggested way.
Edit:
They are 2 ways I see, by session:
data_dict = {name1:misc1, name2:misc2, etc...}
request.session['hyperlinks'] = data_dict
Or passing to the template the data if no session backend:
data_dict = {name1:misc1, name2:misc2, etc...}
encoded = urllib.urlencode(data_dict)
return render(request, "my_template.html", {"url_params":encoded,}
and
Go to results

implementing a custom UploadHandler in django

We've got some clients sending a custom POST of a data blob to our django servers.
They do things in a rather funky way that I'd rather not get into - and we've since moved on from making that particular format the norm. To make further implementations of our upload protocol more streamlined, I was looking to roll a custom UploadHandler in django to make our data handling in the views a bit more streamlined.
So, moving forward, we want all code in the views to access our POSTs via the:
data = request.FILES['something']
So, for our new submissions, we're handling that dandily.
What I'd like to be able to do is get the upload handler we've made, affectionately called LegacyUploadHandler(), to populate the request.FILES dictionary with the right parts, so the code in our view can access the parts the same way.
So, my question:
How does a custom uploadhandler actually populate the request.FILES dictionary? The django documentation doesn't really give a descriptive example of doing that.
Our particular desire is that we have a singular blob of data coming in. We custom parse it and want it to appear as the request.FILES dictionary.
The current code as it stands right now does this:
def handle_raw_input(self, input_data, META, content_length, boundary, encoding=None):
files_dict = {}
files_dict = magic_parser(input_data.read())
#now what do I do?
I see examples of setting a files MultiValueDict in the http.MultiPartParser, but that seems to be outside the scope/control of where I am in my handlers.
Any ideas of how to actually do the return value? Or am I trying to populate the request.FILES object the completely wrong way?
From handle_raw_input you have to return a tuple of what will be POST and FILES on the requst. So in your case it's something like:
def handle_raw_input(self, input_data, META, content_length, boundary, encoding=None):
files_dict = magic_parser(input_data.read())
return QueryDict(), files_dict
The magic_parser should return a MultiValueDict of the form {'filename': fileobj}. A fileobj is an instance of some suitable django.core.files.File subclass (or may be that class itself).