Need user to pick from a list to connect two users in YESOD - yesod

I need general guidance on how to structure a YESOD app. I would like to keep the app as "RESTful" in design as possible.
The user searches all the other users to find one to connect with. I show the possible connections using Hamlet:
$forall (pid, person, mEmail, mPhone) <- displayPeopleRecs
<p>
<a href=#{CreateFundR pid}>#{personNickName person}
$maybe email <- mEmail
#{emailEmail email}
$maybe phone <- mPhone
#{phoneNumber phone}
However, now when a user clicks on a link they go to the /createfund/ page as a GET request which is not what I want, I want to use POST or something else.
Can anyone explain what the correct solution is here? Do I make a form for each person what the search produces and have a submit button for each possible person? That seems silly. Is it better to use Julius and change the onclick handler for the link to submit a POST instead of a GET to /createfund ?
Here is the relevant line from my config/routes:
/createfund/#PersonId CreateFundR POST
By the way, I can see how to make this work by using a form and a submit button:
$forall (pid, person, mEmail, mPhone) <- displayPeopleRecs
<p>
<form method="post" action="#{CreateFundR pid}">
<table>
<tr>
<td>
#{personNickName person}
$maybe email <- mEmail
<br>
#{emailEmail email}
$maybe phone <- mPhone
<br>
#{phoneNumber phone}
<td>
<input type="submit" value="Create Fund">
That will work for my needs, but I'd really like to allow the user to just click the link. Is this poor design? Or just a matter of taste?

If you use an AForm / MForm, the form will be automatically generated for you (using Tables or Divs). That should simplify things for you.
If you want to manually style it, you can do something like this when using a form: How to make button look like a link?. Most people end up creating styled buttons for such actions anyways (think of your standard CRUD app with Edit, Delete buttons, etc.).
If you go down the path of trapping link clicks and do ajax Post, it will not degrade nicely if javascript is disabled so something you need to watch out for.
HTH

Related

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)

Getting dropdown value from template django

I am facing an issue working with django ( using shopcart ). I want to add a select options field to change dynamically an item suscription in the cart, but I am not getting the value selected from the template.
In my template where I display the cart I have :
<form action="" method="GET">{%csrf_token%}
<select name="suscr" title="suscr">
<option value="" selected>Suscribe</option>
<option value="1" name="suscr" >Weekly</option>
<option value="2" name="suscr">Monthly</option>
</select>
</form>
I want to select an option and then, if I press 'Checkout' to have the cart updated.
Appart from that, I believe its missing a method modifying the item in cart.py.
Any ideas would help.
Thanks
The above form is inside a loop
{% for item in cart %}
What i propose you to do is not python-oriented but all javascript for the most part as, from the description, we assume that what you are dealing with is going all at the client-side.
As you are dealing with a shopping cart, what i'd do is storing what the user is checking in a sessionStorage so that the information would persist while the user navigates through your website even with multiple tabs. As the user might just be "walking around" you shopping website, there's no need to push things to the database without even knowing if the user wants that. Just remove the form and keep with the select, then you get what the user selected appending an attribute to select: <select onchange=my_function(this.value)>...</select> and then, inside my_functionin a script change whatever you want to the page.
When the user enters the shopping cart page you show him what he selected so far getting the items from the sessionStorageand then, if he/she confirms that wants to buy, then submit a form to the server-side, update the database and proccess that as your workflow states.
tl;dr: store the options in sessionStorage, just post to the server at the end.
For help on the server-side update your question with more info about the cart.py

Append information at the end of the URL

I have an application which is very similar to forum. Users can participate in posting content. When user click on a topic it goes to that topics page which shows all the discussion related to that topic. I have a side bar just like in the stackoverflow where it shows similar questions which shows topics related to the title of the topic in the current page.
Here is the sidebar template code:
<div class="box">
<h2>{% trans %}Related Topics{% endtrans %}</h2>
<div class="topic-related">
{% for thread_dict in similar_threads.data() %}
<p>
{{ thread_dict.title|escape }}
</p>
{% endfor %}
</div>
</div>
I have an application that tracks user clicks. Assume that user went to a topic and after seeing the related topics she clicks on a topics and go to that page. But I have no way of distinguishing if the user directly went to this topics other than using related topics section.
So I thought may be I can add something like fromRelatedTOpics to the end of the url. What is the best way to accomplish this?
{{ thread_dict.title|escape }}
Is this possible?
The keyword you are looking for is referer. If the user clicked a link to your site, the referer may tell you where he came from (this depends on the browser setting). To access the referer from a view, you have to access the META attribute of the request, i.e.:
request.META.get('HTTP_REFERER')
You may want to look into this django snippet to get some inspiration.
If you want this information inside the template, you can try this:
{{ request.META.HTTP_REFERER }}
What you can do is to redirect all clicks to "related topics" to a single view, also pass the related topic id (or any unique value which can identify that topic in backend) to this view.
Now whenever this view is executed you can safely assume that someone clicked on "related topic", so record this behavior. Using referer (as described by #steinar) you can also record the parent page url from where relative link was clicked.
After recording the behavior you can redirect user to "related topic" using the unique id passed to this view.

Using Bootstrap wysiwyg text editor in Django Form

I am using Django and Bootrap 2.32. I want to include this wysiwyg-bootrap-themed text editor: http://mindmup.github.io/bootstrap-wysiwyg/. The usage of this editor is fairly simple, including
$('#editor').wysiwyg();
in the JS-declaration will render each
<div class=editor></div>
into a beatiful wysiwyg text-editor.
Now the problem: I want to include this editor into one of my django form field. I have the single form:
class Article_Form(ModelForm):
Article_text = CharField(widget=Textarea(attrs = {'id' : 'editor'}))
class Meta:
model= Article
, whereas the Article model includes one simple CharField . Is there any chance, to get the editor work inside the Article_text form-field? With the above-mentioned widget, the created textarea cannot be controlled by the wysiwyg-editor-control buttons. Wrapping the form-template-tag like this
<div id="editor">
{{ Article_Form.Article_text }}
</div>
doesn't work either. The problem thus is that Django creates a textarea, wheras the editor would need a <div> to render correctly. Do you guys have any idea how to get this to work (without refering to django-wysiwyg).
Thanks!
I don't know enough about Django but I wrote the editor you're referring to, so here's a suggestion. Assuming the other answer on this page is correct and you can't generate a div directly, you can generate a text area using whatever Django templates you would normally do, then assign two events:
1) page onload event that would copy the textarea contents into the div, something like
$('#editor').html($('#textarea').val())
2) form onsubmit event that would reverse copy the current div contents into the textarea before it gets submitted
$('#textarea').val($('#editor').html())
Take a look at this.
Summernote is a simple WYSIWYG editor based on Twitter's Bootstrap.
django-summernote plugin allows you to embed Summernote into your Django admin page very handy.
https://github.com/lqez/django-summernote
Are you sure that this "plugin" doesn't work with textarea?
{{ Article_Form.Article_text }}
will be rendered to something like:
<textarea cols="40" id="id_Article_text" name="Article_text" rows="10"></textarea>
So there is a chance that you can initialize the wysiwyg editor like:
$('#id_Article_text').wysiwyg();
However after checking the plugin, I doubt that would be possible since it is using contenteditable="true" attribute of HTML5 and probably the plugin works with div only.
So there is no way you can make it work natively with Django form. The solution should be display other fields of your form manually, hide the one with textarea and display the editor instead:
<form action="" method="POST">
{{ Article_Form.field1 }}
{{ Article_Form.field2 }}
<div class=editor></div>
{% csrf_token %}
<input type="submit" value="Submit" id="submit-btn" />
</form>
Then you can use JS to submit your form:
$('#submit-btn').click(function (e) {
e.preventDefault();
$.ajax({
// do your magic here.
// note that you can get the content of the editor with: $('#editor').cleanHtml();
})
});
This way is hackish I agree so I don't recommend you go for it, just find other plugin then. Also please read PEP 8 carefully.
Hope it helps.
Take a look at this repo: https://github.com/rochapps/django-secure-input
I think it solves most of your problems.

Django: How do I position a page when using Django templates

I have a web page where the user enters some data and then clicks a submit button. I process the data and then use the same Django template to display the original data, the submit button, and the results. When I am using the Django template to display results, I would like the page to be automatically scrolled down to the part of the page where the results begin. This allows the user to scroll back up the page if she wants to change her original data and click submit again. Hopefully, there's some simple way of doing this that I can't see at the moment.
It should already work if you provide a fragment identifier in the action method of the form:
<form method="post" action="/your/url#results">
<!-- ... -->
</form>
and somewhere below the form, where you want to show the results:
<div id="results">
<!-- your results here -->
</div>
This should make the page jump to the <div> with ID results.
It is complete client site and does not involve Django, JavaScript or similar.
You need to wrap your data into something like this:
<div id="some-id">YOUR DATA TO BE DISPLAYED</div>
and if you make redirect in your view you need to redirect to url: /some-url/#some-id
if you don't make redirect you need to scroll to the bottom using javascript (but note that redirect is preffered way to use in view after saving data).