reading file in a django view function - python

EDITED in response to comments and answers:
I am new to django and web development and I feel like I'm missing something basic about how to use django views.
I have a django app that I set up following the instructions in the django tutorial: here. Specifically, I end up with the autogenerated directory and file structure described there:
mysite/
manage.py
settings.py
urls.py
myapp/
models.py
views.py
templates/
*.html
static/
*.css
In my app I receive some user input from a template form and save it in my model in a function in views.py.
Before doing this I want to run some functions to check the input - depending on what it is I decide whether or not and where to put it in the database and also what content to display to the user next.
For example, one thing I want to do is check whether the words that were input are in the dictionary. I have a word list in a text file and I want to check whether the words from the input are in that list.
I want to be able to do something like:
wordlist = set(w.strip() for w in open(filename).readlines())
Where should I put this text file and how can I refer to it (in order to open it) in views.py? Where should I put that line of code - is there a way to only make this set once and then access it whenever any user submits input?
Note that I tried just putting the text file in myapp/ and then doing open(filename) but I get an error:
IOError No such file or directory.
I also tried to put the file in static/ and then do open(STATIC_URL + filename) but I get an error:
NameError Name 'STATIC_URL' is not defined.
However I do have from django.contrib import staticfiles so it should be defined.

This is a very old post, but I was doing something similar and here is my solution of how to read text content in Django view.py
import os
def your_view_function(request):
module_dir = os.path.dirname(__file__) #get current directory
file_path = os.path.join(module_dir, 'data.txt') #full path to text.
data_file = open(file_path , 'rb') #I used'rb' here since I got an 'gbk' decode error
data = data_file.read()
# print("data=", data)
return whatever_you_need

Django is just Python. There are no special rules about accessing files in Django, you do it just as you would with any other Python script.
You don't give any examples or reason why open(filename) doesn't work. Assuming filename is an absolute path, and that the user that Django is running as has permission to open the file, it should definitely work. (Although note that relying on opening a file may not be the best design when it comes to a multi-user web site.)

Related

how to get context of a text file and add it to html file by python using Flask

this is the exercise(you can use only two html templates (the index and the movie). When the user navigates to a movie specific page the description and title must be read from a file called {movie_id}.txt within the project dir and then passed to movie template.)
i tried this ===>>
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/index")
def index():
return render_template("index.html")
#app.route("/marvel")
def marvel():
with open("marvel.txt") as file:
return render_template("movie.html", text=file.read())
however it only printed the html codes inside the text file and didnt use it as html codes.
If I understand you correctly, the text file contains html tags, which are automatically escaped within the template. Use the Jinja2 filter safe within the template to suppress this behavior.
{{ text | safe }}
An alternative to declare content outside of the template as safe is the following. You can find the documentation here.
from flask import Markup
#app.route("/marvel")
def marvel():
with open("marvel.txt") as file:
html = Markup(file.read())
return render_template("movie.html", text=html)
Note that the default behavior has been implemented for security reasons and you are aware of what the contents of the text file can do within your page.
Perhaps your task allows you to reconsider your data structure and application design so that you can format the html entirely within the template and not within a plain text file.

Flask app rendering some variable urls from HTML docs in folder but not others HTML docs in the same folder

My Flask app renders all templates in the template folder, including all blog posts in a blog folder within the templates folder. However, I have the exact structure for my app's glossary as I have for the blog - a folder called 'glossary' within the templates folder. But, it's quirky. It renders some html documents but not others from that same folder. It renders 0-day.html every time I click a link with that dynamic url or directly type in /0-day; but not act.html using /act. I have 180 html files in the glossary folder and about half render and the rest return a 404.
I've been researching this for a month now, and today I switched the glossary structure by creating a blueprint instead. I used this tutorial: https://www.youtube.com/watch?v=WteIH6J9v64. I got everything running as normal, except the same issue with the glossary persists with the blueprint setup as well.
Assuming everything else works, and it does:
Glossary Term:
#glossary.route("<termname>", methods=["POST","GET"])
def term(termname='story'):
try:
visits(termname)
return render_template(f"{termname}.html", glossary=True, termname=termname)
except Exception as e:
return page_not_found(e)
As you can see below, I have my blog setup the same way:
Blog Posts
#app.route("/blog/<postname>", methods=["POST","GET"])
def post(postname='distant-idealism-introduction'):
try:
visits(postname)
return render_template(f"/blog/{postname}.html", blog=True, postname=postname)
except Exception as e:
return page_not_found(e)
The only difference is that the blog is routed from the routes.py now and the glossary terms from the glossary.py blueprint. However, when there was no blueprint I was rendering everything from the routes.py file, so the blueprint setup is not the cause.
I apologize, but because this problem is so confusing, I don't know what else to add. It's even difficult to research because I always get results like the YouTube video above - either about blueprints, building routes, or something Flask in general. I never get any search result even close to my issue. If more info is required just let me know, please.
Thank you in advance.
Some problems I found:
The URL rule is missing a start slash:
#glossary.route("/<termname>", methods=["POST","GET"])
Since your templates about glossaries were put in a glossary folder, your template path should be /glossary/act.html:
return render_template(f"/glossary/{termname}.html", glossary=True, termname=termname)

Django Upload Image in specific folder without FileField or ImageField and MEDIAROOT

My App needs to upload different profile images in different folders inside the static folder.
One more thing, I'm not using models, I just want to take the picture I choose in html input file and copy to the specific folder.
Here is my folder tree. Where I want to save the uploaded image is in MYPROJECTFOLDER/static/profile/<TheUserSpecificFolder>/ that's where I don't want to use MEDIA_ROOT, becouse in media root I can't create a specific folder to each user. (I don't know if this is correct, if there is a way to create a specific folder to each user in the /media/ folder without using ImageField or FileField, please tell me).
Here is my folder tree:
MYPROJECTFOLDER
|
|------myproject/
|
|------myapp/
|
|------static
| |-------profile
| |------folder_user1
| |------ uploadedpicture.jpg #Here is where I want to upload
| |------folder_user2
Here is my uploadpic.html
<form action="{% url 'upload' %}" enctype="multipart/form-data" method="POST">
{% csrf_token %}
<input type="file" name="avatar" accept="image/gif, image/jpeg, image/png">
<button type="submit">Upload</button>
</form>
Here is my views.py
from django.shortcuts import render, HttpResponse, redirect
from . import forms
import os
def upload(request):
img = request.FILES['avatar']
#This just create the folder where I want to save the image.
if not os.path.exists('static/profile/' + str(request.session['user_id'])):
os.mkdir('static/profile/' + str(request.session['user_id']))
#NOW HERE IS WHERE I WANT TO WRITE THE CODE THAT SAVE THE IMAGE INTO THE FOLDER I JUST CREATED
return redirect('companyedit')
Since you say that:
I don't want to use MEDIA_ROOT, becouse in media root I can't create a specific folder to each user
Actually, you can. You asked a similar question before and the answer I posted allows you to do that. Simply put, yes, you can create separate folders for users in MEDIA_ROOT. See this answer.
Anyway, if you still want to upload images in a custom folder manually, well, you can do it like this:
def upload(request):
img = request.FILES['avatar']
img_extension = os.path.splitext(img.name)[1]
user_folder = 'static/profile/' + str(request.session['user_id'])
if not os.path.exists(user_folder):
os.mkdir(user_folder)
img_save_path = "%s/%s%s" user_folder, 'avatar', img_extension
with open(img_save_path, 'wb+') as f:
for chunk in img.chunks():
f.write(chunk)
Attention!
As per the suggestion made by dahrens in the comment below, here are the reasons why you should keep the static files and media files in separate locations:
Static files are considered to be safe as they come from you, the developer - media files instead come from user land and might need additional attention, so they can not be considered safe without checks.
Media/uploaded files will keep growing as more and more users upload files. With your current approach, you are likely to run out of storage space.
Almost every serious web application hosts the uploaded media files in a separate server, so that storage won't become a problem. That is why it is a good idea to keep uploaded images in MEDIA_ROOT. Because all you have to do is change the value of MEDIA_ROOT and Django will save images there.

How to unit test urls.py when included by project?

How can I run unit tests to validate that a certain URL calls a particular function?
I want to do something like this:
class HomePageTest(TestCase):
def test_root_url_resolves_to_list_view(self):
found = resolve('/testme/')
self.assertEqual(found.func.func_name, ListView.__name__)
#self.assertEqual(found.func, ListView.as_view())
But lets imagine the apps urls.py is included in the projects urls.py under something like:
url(r'^submodule/$', include('fhqna.urls')),
How can I write the test included in the app so it checks the url "/testme/" indepent of how it is included? ("/submodule/testme/" in this example)?
You can configure urls for test case
class HomePageTest(TestCase):
urls = 'fhqna.urls'
def test_root_url_resolves_to_list_view(self):
found = resolve('/testme/')
self.assertEqual(found.func.func_name, ListView.__name__)
Or give a name to your url and resolve it by this name regardless of actual url is used. In this case you don't need to configure urls for TestCase.

How to get a url map in django? [duplicate]

Is there a way to get the complete django url configuration?
For example Django's debugging 404 page does not show included url configs, so this is not the complete configuration.
Django extensions provides a utility to do this as a manage.py command.
pip install django-extensions
Then add django_extensions to your INSTALLED_APPS in settings.py. then from the console just type the following
python manage.py show_urls
Django is Python, so introspection is your friend.
In the shell, import urls. By looping through urls.urlpatterns, and drilling down through as many layers of included url configurations as possible, you can build the complete url configuration.
import urls
urls.urlpatterns
The list urls.urlpatterns contains RegexURLPattern and RegexURLResolver objects.
For a RegexURLPattern object p you can display the regular expression with
p.regex.pattern
For a RegexURLResolver object q, which represents an included url configuration, you can display the first part of the regular expression with
q.regex.pattern
Then use
q.url_patterns
which will return a further list of RegexURLResolver and RegexURLPattern objects.
At the risk of adding a "me too" answer, I am posting a modified version of the above submitted script that gives you a view listing all the URLs in the project, somewhat prettified and sorted alphabetically, and the views that they call. More of a developer tool than a production page.
def all_urls_view(request):
from your_site.urls import urlpatterns #this import should be inside the function to avoid an import loop
nice_urls = get_urls(urlpatterns) #build the list of urls recursively and then sort it alphabetically
return render(request, "yourapp/links.html", {"links":nice_urls})
def get_urls(raw_urls, nice_urls=[], urlbase=''):
'''Recursively builds a list of all the urls in the current project and the name of their associated view'''
from operator import itemgetter
for entry in raw_urls:
fullurl = (urlbase + entry.regex.pattern).replace('^','')
if entry.callback: #if it points to a view
viewname = entry.callback.func_name
nice_urls.append({"pattern": fullurl,
"location": viewname})
else: #if it points to another urlconf, recur!
get_urls(entry.url_patterns, nice_urls, fullurl)
nice_urls = sorted(nice_urls, key=itemgetter('pattern')) #sort alphabetically
return nice_urls
and the template:
<ul>
{% for link in links %}
<li>
{{link.pattern}} ----- {{link.location}}
</li>
{% endfor%}
</ul>
If you wanted to get real fancy you could render the list with input boxes for any of the regexes that take variables to pass to the view (again as a developer tool rather than production page).
This question is a bit old, but I ran into the same problem and I thought I would discuss my solution. A given Django project obviously needs a means of knowing about all its URLs and needs to be able to do a couple things:
map from a url -> view
map from a named url -> url (then 1 is used to get the view)
map from a view name -> url (then 1 is used to get the view)
Django accomplishes this mostly through an object called a RegexURLResolver.
RegexURLResolver.resolve (map from a url -> view)
RegexURLResolver.reverse
You can get your hands on one of these objects the following way:
from my_proj import urls
from django.core.urlresolvers import get_resolver
resolver = get_resolver(urls)
Then, you can simply print out your urls the following way:
for view, regexes in resolver.reverse_dict.iteritems():
print "%s: %s" % (view, regexes)
That said, Alasdair's solution is perfectly fine and has some advantages, as it prints out some what more nicely than this method. But knowing about and getting your hands on a RegexURLResolver object is something nice to know about, especially if you are interested in Django internals.
The easiest way to get a complete list of registered URLs is to install contrib.admindocs then check the "Views" section. Very easy to set up, and also gives you fully browsable docs on all of your template tags, models, etc.
I have submitted a package (django-showurls) that adds this functionality to any Django project, it's a simple new management command that integrates well with manage.py:
$ python manage.py showurls
^admin/
^$
^login/$
^logout/$
.. etc ..
You can install it through pip:
pip install django-showurls
And then add it to your installed apps in your Django project settings.py file:
INSTALLED_APPS = [
..
'django_showurls',
..
]
And you're ready to go.
More info here -
https://github.com/Niklas9/django-showurls
If you want a list of all the urls in your project, first you need to install django-extensions
You can simply install using command.
pip install django-extensions
For more information related to package goto django-extensions
After that, add django_extensions in INSTALLED_APPS in your settings.py file like this:
INSTALLED_APPS = (
...
'django_extensions',
...
)
urls.py example:
from django.urls import path, include
from . import views
from . import health_views
urlpatterns = [
path('get_url_info', views.get_url_func),
path('health', health_views.service_health_check),
path('service-session/status', views.service_session_status)
]
And then, run any of the command in your terminal
python manage.py show_urls
or
./manage.py show_urls
Sample output example based on config urls.py:
/get_url_info django_app.views.get_url_func
/health django_app.health_views.service_health_check
/service-session/status django_app.views.service_session_status
For more information you can check the documentation.
Are you looking for the urls evaluated or not evaluated as shown in the DEBUG mode? For evaluated, django.contrib.sitemaps can help you there, otherwise it might involve some reverse engineering with Django's code.
When I tried the other answers here, I got this error:
django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
It looks like the problem comes from using django.contrib.admin.autodiscover() in my urls.py, so I can either comment that out, or load Django properly before dumping the URL's. Of course if I want to see the admin URL's in the mapping, I can't comment them out.
The way I found was to create a custom management command that dumps the urls.
# install this file in mysite/myapp/management/commands/urldump.py
from django.core.management.base import BaseCommand
from kive import urls
class Command(BaseCommand):
help = "Dumps all URL's."
def handle(self, *args, **options):
self.show_urls(urls.urlpatterns)
def show_urls(self, urllist, depth=0):
for entry in urllist:
print ' '.join((" " * depth, entry.regex.pattern,
entry.callback and entry.callback.__module__ or '',
entry.callback and entry.callback.func_name or ''))
if hasattr(entry, 'url_patterns'):
self.show_urls(entry.url_patterns, depth + 1)
If you are running Django in debug mode (have DEBUG = True in your settings) and then type a non-existent URL you will get an error page listing the complete URL configuration.

Categories