External links redirect to localhost [flask] - flask

I have a small flask application that I'm running on localhost right now. most things are working fine but I've been banging my head for last few hours over this issue now - When I try to put an external link on my template, it always redirects to localhost.
I have a main.py file where I have placed a variable
testURL = "https://www.google.com"
On my template file, home.html, I place the hyperlink
More...
Clicking on that 'More...' hyperlink I wanted it to open a new tab to google.com but it's simply opening up a new tab with localhost http://127.0.0.1:5000/ - it's something very basic that I'm missing on I think.
Please point me in the right direction!
TIA

As mentioned, you need to pass that variable to the template:
render_template('home.html', testURL=testURL)
Another useful method, if you want to send that variable to every page, is to use a context processor:
#app.context_processor
def processor():
""" This function injects vars into every page """
return dict(SITE_TITLE='My Site')
Then use {{SITE_TITLE}} in any template.

Related

Why is flask turning %20 into %2520?

I created a personal CMS project where each page is stored in the database with the following columns: title, url_safe_title, and content.
To create the url_safe_title, I used urllib.parse.quote() on the original title. So if the page title is "My Page", the url_safe_title will be stored as "My%20Page".
On templates, I'd build URLs using url_for('core.page', page_name = page.url_safe_title), where page_name is the expected variable in the view function.
#core.route('/<string:page_name>')
def page(page_name):
# find the relevant entry in db
return render_template('template.html', page = page)
However, the resulting URL becomes "www.example.com/My%2520Page" instead of the expected "www.example.com/My%20Page". I checked the url_safe_title value stored in the database, and it's the correct value ("My%20Page").
Interestingly, "My%2520Page" worked when trying to query for a page that has url_safe_title as "My%20Page" when I was hosting this app locally. However, it all fell apart when I hosted it online. Unfortunately, the host is a limited cPanel host without any access to the terminal, so I'm unable to find out what the OS is. I only know that the python version is 3.7.8, and my local python version is 3.7.4.
I've also tried using the |safe jinja filter when building the URL url_for('core.page', page_name = page.url_safe_title|safe), but that didn't help either. I passed the page.url_safe_title as a variable on its on to show on the page, and "My%20Page" was displayed.
%2520 means it is getting encoded twice. You should not encode it before storing in the database. It is just a string.

Django view getting called twice (double GET request)

I'm creating a classifieds website in Django. A single view function handles global listings, city-wise listings, barter-only global listings and barter-only city-wise listings. This view is called ads.
The url patterns are written in the following order (note that each has a unique name although it's tied to the same ads view):
urlpatterns = patterns('',
url(r'^buy_and_sell/$', ads,name='classified_listing'),
url(r'^buy_and_sell/barter/$', ads,name='barter_classified_listing'),
url(r'^buy_and_sell/barter/(?P<city>[\w.#+-]+)/$', ads,name='city_barter_classified_listing'),
url(r'^buy_and_sell/(?P<city>[\w.#+-]+)/$', ads,name='city_classified_listing'),
)
The problem is that when I hit the url named classified_listing in the list above, the function ads gets called twice. I.e. here's what I see in my terminal:
[14/Jul/2017 14:31:08] "GET /buy_and_sell/ HTTP/1.1" 200 53758
[14/Jul/2017 14:31:08] "GET /buy_and_sell/None/ HTTP/1.1" 200 32882
This means double the processing. I thought urls.py returns the first url pattern matched. What am I doing wrong and what's the best way to fix this? All other calls work as expected btw (i.e. only once).
Note: Ask for more information in case I've missed something.
Great explanation to understand these type of occurences: https://groups.google.com/d/msg/django-users/CRMMYWix_60/KEIkguUcqxYJ
This issue has nothing to do with how url patterns are ordered in urls.py.
Like pointed out in the comments under the question, this has to do with problematic asset references in the HTML template.
What does that mean?
For instance, try curl -i http://localhost:8000/example/ >> output.txt in your terminal. Then open up output.txt in your editor of choice. Now search for href or src attributes where values are None (or otherwise malformed). That's one reason a double call is being created. That was the reason for me. I removed these, and the double call disappeared.
There's this old - but relevant - writeup about how to comprehensively diagnose this problem on your machine here: https://groups.google.com/forum/#!msg/django-users/CRMMYWix_60/KEIkguUcqxYJ
Happy testing.
As I can't comment on other answers, just to add for future wanderers that for me the "problem" was in a correctly formed but yet for the browser instructing <iframe src="#"..> tag. On django server the view was rendering twice, once with original request and then again by the hidden iframe element that I used for some of the modal popups later in the page usage.
After emptying the src attribute like <iframe src=""..> a second request is no longer initiated and my modals work fine.
The solution actually is from the link posted already in answers before [https://groups.google.com/forum/#!msg/django-users/CRMMYWix_60/KEIkguUcqxYJ][1]
where it is explained:
Note that it's a URI. That means something that is retrieved. Since
you've used the value "#fff", that will be interpreted by the browser as
a reference to the current page (#fff being an anchor, and not passed to
the server). Ergo, a second request is made.
that the iframe src # (anchor) is instructing the browser to load again the same URL, for the iframe element in my case.
I indeed had several style elements with #fff colors inside and whatnot, but this wasn't it, as browsers are smart enough to recognize this is not an anchor.
With available tools (browser only) I found to be easy to debug and find these initiation href/src attributes over the Network tab of your browser developer tools - in Chrome is just by clicking the Initiator link of the corresponding row - giving you the exact line from the page source that initiated the request to the same URL.
I struggled with the same problem and just wanted to share my experience with it. I had double requests all over my application but everything seemed to work as expected apart form it.
What Daniel Rossman pointet out in the comments was actually also true for my problem. I had a <link rel="shortcut icon" href="#"> in my base template which caused the double request, because of the #, which is a reference to the page itself. Once i removed it, i had no double requests anymore.
Hope this answer can save someone some debugging time.
I got double request in view function, in my scenario, this went wrong:
<img id="profile-img" src="#" alt="" class="profile-cover">
by setting src="" dismiss double request. it was a silly thing, I just thought it apply to a then must apply to img, but img actually send another request.

How to serve a text file at root with Django

I got a site, say it's "www.site.com". I need to serve a text file at the root, so that "www.site.com/text.txt" will show up.
I read through this answer: Django download a file, and I used the "download" function.
However I am at a loss how to configure the URL. Can someone help me out?
Say I put this this into my url.py,
url('^(?P<path>.*)/$', san.views.FileDownload.as_view()),
This then supersedes all my other url patterns and render them useless. How do I make this work? Thanks!
Put it as the last urlpattern in your urls.py to ensure it doesn't sccop up everything. It should not have the trailing / either, i.e.
url('^(?P<path>.*)/?$', san.views.FileDownload.as_view()),
This will match the request "/YOUR_FILE.txt", and is also case-insensitive.
url(r'^(?i)YOUR_FILE.txt$', san.views.FileDownload.as_view()),

Error when trying to load Django custom filters into template

I've inherited a Django application that I need to modify using a custom template filter. I'm absolutely new to Django and am quite mystified by it. I thought I had followed the instructions exactly, and also followed all the advice from other posts on the subject, but I still get an error when I include the following line in my template:
{% load mlgb_custom_filters %}
My directory structure is as follows:
mysite (i.e. the project)
__init__.py
mlgb/ (i.e. the app)
__init__.py
templatetags/
__init__.py
mlgb_custom_filters.py
The code of mlgb_custom_filters.py is as follows:
from django import template
from django.template.defaultfilters import stringfilter
register = template.Library()
#register.filter(name='fix_dashes')
#stringfilter
def fix_dashes( value ):
return value.replace( '--', 'DASH' )
if __name__ == "__main__":
testvar = fix_dashes( "ouch -- ow -- I hate django" )
print testvar
As you can see, I've added a 'name = main' section to let me run it in standalone mode, just to check that there are no errors in that particular file, and it's fine when run in standalone mode.
Based on someone else's advice, I've also tried importing it into another file, just to see whether there was an import error, and once again, it was fine if I added this to the end of settings.py (while using the dev server):
try:
import mlgb.templatetags.mlgb_custom_filters
except Exception, exc:
print 'error importing mlgb_custom_filters'
print exc
Also, INSTALLED_APPS in settings.py includes the line 'mysite.mlgb', and I have also tried putting just 'mlgb' instead of 'mysite.mlgb' there, as yet another person suggested. And I restarted the dev server every time I made a change.
I think I have tried every single suggestion that I have found on the web until now. Does anyone have any new ideas? Could it be anything to do with the fact that I have inherited a directory structure where the template directory is not within the same structure as the application, i.e. it is not under mysite? Scraping the barrel for ideas here! I hope someone can help.
OK, in the situation that I was in when first posting this question, it seems all I actually needed to do was touch a wsgi file under my appname/apache directory to force the application to be refreshed. Yesterday's initial answer was a red herring. Basically I should have touched the file myproject/myapp/apache/myapp.wsgi. Then maybe restart Apache for good measure? But the confusion was caused by the fact that apparently it wasn't enough either simply to restart Apache or to manually recompile the Python. In order to pick up my changes, seems like I needed to touch that wsgi file. Then all is well.
I can now post an answer to my own question thanks to the help of my colleague Masud Khokhar, whose brilliant detective work has saved the day. To recap, my application worked fine until I added a 'load' statement to one of my template files, to load a 'custom filters' module. Masud identified that now I needed to use a full/absolute path to the template file in urls.py instead of a relative one as I had before (and which worked before, until it needed to load the custom filters module). So, in urls.py, I had a section of code as follows:
url(r'^book/(?P<object_id>\d+)/$', 'list_detail.object_detail',
kwargs={
'queryset':Book.objects.all(),
'template_name' : 'mlgb/mlgb_detail.html'
},
name='mlgb_detail'
),
Instead of this:
'template_name' : 'mlgb/mlgb_detail.html'
I needed something like this:
'template_name' : '/THE_FULL_PATH/mlgb/templates/mlgb/mlgb_detail.html'
Made that change - sorted! Thank you once again, Masud.

How do you acquire the rewritten CFWheels URL of an given page?

CFWheels has the URLFor() function for getting the internal URL based on supplied arguments. Is there a way to get the internal URL without supplying any arguments?
For example:
Given a user navigates to "http://somedomain.com" or "http://somedomain.com/about/" or "http://somedomain.com/contact/" is there a method like ReWrittenURL() that returns something like "/" or "/about/" or "/contact/"?
Using URLFor() with no arguments returns "/home/index" or "/about/index" or "/contact/index".
CGI.SCRIPT_NAME returns "/rewrite.cfm"
Obviously with Javascript using document.location.href I can get what I'm after.
Does CGI.path_info have the value you're looking for?
edit
At first, I deleted this post, being utterly confounded. Now I've done a little test - I downloaded the latest wheels core files (1.1.6), extracted to an IIS 7.5 (with URL Rewrite module installed) + CF9 webserver, and edited the "web.config" file in the core root, setting "enabled='true'" for the rewrite rule. Also, since I was running this example from a subfolder, I changed the path from "/rewrite.cfm" to just "rewrite.cfm". This got me to the point where I was able to successfully requests urls like this:
http://server/wheelstest/wheels/wheels
From here, I edited the layout.cfm under views/wheels, adding:
<cfdump var="#cgi#">
When I then request the above URL (/wheelstest/wheels/wheels), I see the dump for the cgi scope. Under path_info, this is the value: /wheels/wheels.
Next, I added a blank "index.cfm" file under views/wheels.
When I request /wheelstest/wheels, I get this for path_info: "/wheels".
When I request /wheelstest/wheels/, I get this for path_info: "/wheels/".
When I request /wheelstest/wheels/index, I get this for path_info: "/wheels/index".
When I request /wheelstest/wheels/index/, I get this for path_info: "/wheels/index/".
So basically - cgi.path_info is doing for me exactly what you describe you want. What is different about your setup than mine, such that it isn't returning that value for you?
there might be a better way to do this... but here I go anyway
every page gets sent the #params#
<cfdump var="#params#">
<cfoutput>#params.action#/#params.controller#/#params.key#</cfoutput>
<cfabort>
try putting that in a controller and see the results
the problem is that if the objects inside the params object don't exist you get an error. So the path that gets generated needs to check if the struct key exists and edit accordingly.
CGI.Path_Info will give you the desired results. I've been trying different options however they all failed and went into the redirect loop. As soon as I switched CGI.path_info it all started well.