Pass a parameter across views - Django - django

I have the following scenario:
I have created globalModels (Season, Team, Player, Referee). Also, I have created seasonalModel (SeasonTeam, SeasonPlayer, SeasonReferee) as I want to record statistics from a Team every particular season, same with Player and Referee) and also I will aggregate statistics from every SeasonTeam into the globalModel Team.
I am building platform for administration. So I have next urls:
adminSite.urls
url(r'^$', views.homeAdmin, name='homeAdmin'),
url(r'^addGlobal/', include('globalModels.urls', namespace='addGlobal')),
url(r'^addSeasonal/', include('seasonalModels.urls', namespace='addSeasonal'))
globalModels.url
url(r'^$', admin_views.addGlobal, name='addGlobal'),
url(r'^addSeason/', views.addSeason, name='addSeason'),
url(r'^addPlayer/', views.addPlayer, name='addPlayer'),
url(r'^addTeam/', views.addTeam, name='addTeam'),
url(r'^addReferee/', views.addReferee, name='addReferee')
Now, in order not to have to choose the season (foreignKey in every seasonalModel) everytime I want to add a new seasonalModel, I want to make a first step of choosing the season, and then let the administratos choose between adding a seasonalTeam, seasonalPlayer...
How would you accomplish this? I have thought about 2 possibilities:
FRONT END
Display with a list of the seasons registered as divs and with JS get the id that the administrator has click on:
{% for season in seasons %}
<div id="{{ season.season }}" class="adminButton chooseSeason ">
{{ season.season }}
</div>
{% endfor %}
And then pass it inside the url:
$(".chooseSeason").click(function (){
var season = $(this).attr('id');
window.location.href = "http://localhost:8000/admin-site/addSeasonal/" + season + "/";
})
In this case, I have my:
seasonModels.py
url(r'^chooseSeason', admin_views.addSeasonalChooseSeason, name='addSeasonalChooseSeason'),
url(r'^([0-9]{4})-([0-9]{4})/', admin_views.addSeasonal, name='addSeasonal'),
url(r'^([0-9]{4})-([0-9]{4})/addTeam/', views.addSeasonalTeam, name='addSeasonalTeam'),
url(r'^([0-9]{4})-([0-9]{4})/addPlayer/', views.addSeasonalPlayer, name='addSeasonalPlayer'),
But I am missing how to make the register the namespace properly:
addSeasonal.html
<div id="addTeamButton" class="adminButton">
Añadir Equipo
</div>
<div id="addPlayerButton" class="adminButton">
Añadir Jugador
</div>
'addSeasonalTeam' is not a registered namespace inside 'admin-site:addSeasonal'
Any idea on how to avoid this problem?
BACK END
Pass as a ModelForm the available seasons registered, and use the submitted as a parameter passed with the request in order to filter in the view that will be used to add the new object in the database
In this case, if season as a globalModel is a charField, how can I force the form to be a list of option with the seasons registered insted of a charField expecting an input?
Sorry for the long post, I hope you could understand my intention and help me.
Thanks in advance!
PR

Related

Opencart 3.0.2.0 and Journal 3 theme customer name in Top Menu

I want to add customer first name on Journal theme top menu module. I am adding {{ text_logged }} in top-menu.twig but it can not get text_logged from controller. How can I get text_logged from catalog/controller/common/header.php?
{% if logged %}
{{ text_logged }}
{% endif %}
$data['text_logged'] = sprintf($this->language->get('text_logged'), $this->url->link('account/account', '', true), $this->customer->getFirstName(), $this->url->link('account/logout', '', true));
I want to see "Hello John Do" on Journal theme top menu $ US Dollar instead
I had contacted the developer regarding the same issue for the journal theme v3. They told me that it can be displayed using this:
Welcome back, {{ $customer_firstname }} {{ $customer_lastname }} !
to show customer firstname and lastname in menu items.
I have integrated that into my code, and it now shows the customer name, when logged in. No need to edit OC MOD
You need to add your code using ocmod or vqmod to the Journal theme common/header.tpl. I highly recommend do not change the Journal's core codes because of ridiculous cache system (even devs couldn't get rid of it). Also here is a solution : You can edit this one for your purpose

add buttons that populate other fields in built-in templates of Flask-Admin

I would like to add a button to my Flask-Admin create view, and following this question I managed to do so.
Now, assuming that the model passed to that view, say User has:
A one to many relationship with ClassA and ClassB
ClassA has also a one to many relationship with ClassB
And assuming that in my create view I've added some instance of ClassA when creating an instance of User, say my_class_a_instance, I would like that this button:
performs a query on my_class_a_instance, returning any instances of ClassB (or my_class_b_instances) related at that moment with it
populates the form.class_b field in the create template with those results
if possible, pop up some modal window promting the user for confirmation. Possible with #action
My approach so far goes like this:
# templates/admin/cascade_button_create.html
{% extends 'admin/model/create.html' %}
{% block body %}
{% call lib.form_tag(form) %}
<div class="row">
<div class="col-xg-10">
{{ lib.render_form_fields([form.name])}}
</div>
</div>
<div class="row">
<div class="col-xg-10">
<!-- form.cities follows the attributes of sqla model -->
{{ lib.render_form_fields([form.instances_of_a])}}
</div>
<div class="col-xg-2">
<!-- so this button should query any model related to form.cities
and populate the create form with whatever comes out.
Say Street has a one to many relationship, I want this
button to run some method of the form get_instances_of_b_from_instance_of_a(form.instances_of_a) (query_method() for short) that fills
the field form.instances_of_b
If possible I would like to pop up a modal window prompting the user
to confirm this before filling this field.-->
Add with cascade
</div>
</div>
<div class="form-buttons">
{{ lib.render_form_buttons(return_url) }}
</div>
{% endcall %}
{% endblock %}-
I would be registering this view like the documentation says
# admin/views.py
class CascadesView(ModelView):
create_template = 'admin/cascade_button_create.html'
I haven't found information on this, and the templates don't have many comments that help.
Thanks!
EDIT:
I've copied the examples from the flask-admin repo and set mine in https://github.com/diegoquintanav/flask-admin-autopopulate to play with
I looked a bit further into it, and this seems very specific behavior, which is not implemented in flask-admin. I went ahead and had a look at it anyways, and the only way I could think of to easily do this is by using Ajax and a special api route.
So I've added this to your js:
Add with cascade
<script>
function retrieve_location_b_ids(){
// make sure that the user wants to preload the b locations
if (confirm('load location b connected to location a?')){
// look for the selected options
var selected_a_locations = $('#s2id_sub_locations_a').select2("val");
// request the b_ids using the a_ids provided by the user using ajax
var oData = new FormData();
oData.append('selected_a_locations', JSON.stringify(selected_a_locations));
var oReq = new XMLHttpRequest();
oReq.open("POST", "{{url_for('look_up_b_locations_connected_to_a_locations')}}", true);
oReq.onload = function(oEvent) {
if (oReq.status == 200) {
// get the correct b ids back from the ajax request, and use them to load the select2 field
var selected_b_ids_list = JSON.parse(oReq.responseText)
$('#s2id_sub_locations_b').select2('val', selected_b_ids_list);
} else {
alert("Error " + oReq.status + " occurred when retrieving the ids")
}
};
oReq.send(oData);
}
}
</script>
and the flask route which deals with this request:
#app.route('/api/look_up_b_locations_connected_to_a_locations', methods=['POST'])
def look_up_b_locations_connected_to_a_locations():
# use a set in case the same b location is in multiple a locations to prevent duplicates
b_location_set = set()
a_location_list = json.loads(request.form['selected_a_locations'])
for a_location_id in a_location_list:
a_location = SubLocationA.query.get_or_404(a_location_id)
for b_location in a_location.sub_sub_locations_b:
b_location_set.add(str(b_location.id))
return jsonify(list(b_location_set))
It seems to work pretty well, and deals with most edge cases (I hope).

Django: How to make this GET request with a hyperlink?

So if I want a user's name to link to it's profile, I want the link to contain the user's first name and last name in GET form...Do I just hard-code this into the link, or is there a more elegant way of coding this? Here is hard-coded:
<p>
<li role="presentation" class="active">{{ user.fname }}
</li>
</p>
Yes, the more elegant way would be to set up a route that takes, for example, the user's ID (pk) and use either a DetailView set up for the User model or a function view that accepts the ID and retrieves the relevant user. Passing in the first and last name directly means you need to query on both of them (after pulling them out of the querystring) rather than simply querying on the ID as it's passed to you (after the framework politely checks its type, provided you've set up the route correctly).
So your route would look something like url(r'^profile/(?P<pk>\d+)/$', ProfileView.as_view(), name='profile') and your template tag would look something like {% url 'profile' user.id %}.

Submit Button Confusion and Request being sent Twice (Using Flask)

I'm pretty much trying to create a web app that takes 2 svn urls and does something with them.
The code for my form is simple, I'm also using WTForms
class SVN_Path(Form):
svn_url=StringField('SVN_Path',[validators.URL()])
I'm trying to create 2 forms with 2 submit buttons that submit the 2 urls individually so my test3.html looks like this:
<form action="" method="post" name="SVNPath1">
{{form1.hidden_tag()}}
<p>
SVN Directory:
{{form1.svn_url(size=50)}}
<input type="submit" value="Update">
<br>
{% for error in form1.svn_url.errors %}
<span style="color: red;">[{{error}}]</span>
{% endfor %}
</p>
</form>
<form action="" method="post" name="SVNPath2">
{{form2.hidden_tag()}}
<p>
SVN Directory:
{{form2.svn_url(size=50)}}
<input type="submit" value="Update">
<br>
{% for error in form2.svn_url.errors %}
<span style="color: red;">[{{error}}]</span>
{% endfor %}
</p>
</form>
MY FIRST QUESTION is how do I know which submit button was clicked so I can run the proper function on the corresponding svn url. I have tried doing something like
if request.form1['submit'] == 'Update':
if request.form2['submit'] == 'Update':
but that does not work at all. I'm new to web dev in general and flask so a detailed explanation would be helpful.
SECONDLY, since submits weren't working properly I also tried an alternative to keep my work moving so in my .py file I have
#app.route('/test3', methods=['GET','POST'])
def test3():
basepath=createDir()
form1=SVN_Path()
form2=SVN_Path()
if request.method=="POST":
if form1.validate_on_submit():
svn_url = form1.svn_url.data
prev_pdf=PDF_List(svn_url,basepath,'prev') #some function
if form2.validate_on_submit():
svn_url2 = form2.svn_url.data
new_pdf=PDF_List(svn_url,basepath,'new') #some function
return render_template('test3.html', form1=form1, form2=form2)
CreateDir is a function that creates a directory in the local /tmp using timestamps of the local time.
Whenever I go the webpage it creates a directory, lets call it dir1, since its calling CreateDir. Thats what I want, but when I click submit on the form it creates another directory dir2 in the tmp folder which is NOT what I want since I want everything to being the same dir1 directory.
In addition when I put a url in one of the forms and click submit, it automatically puts it the same value in the 2nd form as well.
Sorry if this is really long and possibly confusing, but any help is appreciated.
:) Let's see if we can clarify this a little.
To your first question:
As #dim suggested in his comment, You have a few options:
You can submit your form to separate unique urls. That way you know which form was submitted
You can create two similar but different Form classes (the fields will need different names like prev_svn_url and cur_svn_url). This way in your view function, you instantiate two different forms and you'll know which form was submitted based on form.validate_on_submit()
The third option would be to add a name attribute to your submit button and then change the value attributes to something like 'Update Previous' and 'Update Current'. This way in your view function you can check the value of request.data[<submit button name>] to determine if 'Update Previous' was pressed or 'Update Current'.
To your second question:
Multiple directories are being created because you're calling createDir() each time the page is loaded to show the forms and when the forms get posted. In order to create just once, you'll need some kind of logic to determine that the directory was not previously created before calling createDir()
In addition: Since both forms are from the same SVN_Path class, they read post data exactly the same way, that's why whatever you type in form 1 appears in form 2.
Now for my 2 cents:
I assume you're trying to write some kind of application that takes two SVN urls as input, creates a folder and does something with those URLs in that folder. If this is the case, the way you are currently going about it is inefficient and won't work well. You can achieve this with just one form class having 2 svn_url fields (with different names of course) and then handling all of that in one post.
EDIT: The job of the submit button is to tell the browser that you're ready to send the data on the form to the server. In this case you should only need one submit button (SubmitFiled => when rendered). Clicking that one submit button will send data from both input fields to your view function.
Your form should look something like:
class SVN_Path(Form):
prev_svn_url=StringField('Previous SVN_Path',[validators.URL()])
new_svn_url=StringField('New SVN_Path',[validators.URL()])
and your view function:
def test():
form = SVN_Path()
if request.method == "POST":
if form.validate_on_submit():
basepath = createDir() # Only create dir when everything validates
prev_svn_url = form.prev_svn_url.data
new_svn_url = form.new_svn_url.data
prev_pdf = PDF_List(prev_svn_url, basepath, 'prev')
new_pdf = PDF_List(new_svn_url, basepath, 'new')
...
return render_template('test3.html', form1=form1, form2=form2)

Querying a single field within a Jinja2 template

I'm working on an application where users can enter work requests, and subsequently go in and search for requests. The issue I'm having is building out the request summary screen. Basically, it lists the results of a search query. The snippet from the template is as such:
{% for req in workrequests %}
{{ req.id }} {{ req.customer }} {{ req.dateEntered }} {{ req.Contact }}
{% endfor %}
Here's wher I get hung up. The req.customer, and req.Contact fields are just keys for the customer and contact databases. I want to display the customer name and contact name. I assume the following queries should do the trick:
Customer.query.filter_by(req.customer).one()
Contact.query.filter_by(req.Contact).one()
Problem is, that will return the entire record. I'm just after the name field from both of those tables to put into my template, which is where the problem is. I'm not sure how to proceed with this
Customer.query is a short form of db.session.query(Customer). Use the latter to query for specific columns:
db.session.query(Customer.name).filter_by(id=req.customer).one()
Although I think that what you really want is a single query that gets all the data at once. Something like:
db.session.query(
WorkRequest.id,
WorkRequest.dateEntered,
Customer.name,
Contact.name
).join(
Customer,
Contact
).filter(...)