Uploading files in django admin, download through public site - python

I am running a Django website and I want to be able to upload a file through my admin panel and then have visitors to the main site be able to download it. I am running my site using Django-nonrel, Django FileTransfers and Google App Engine. I believe the upload functionality is working correctly as I am able to see the file in my App Engine Blob Storage. What I can't seem to figure out is how to present a download link to the specified file on the public website. I have pasted the relevant classes below:
I have an app called Calendar, that has the following model:
class CalendarEvent (models.Model):
start = models.DateTimeField(auto_now=False, auto_now_add=False)
end = models.DateTimeField(auto_now=False, auto_now_add=False)
title = models.CharField(max_length=500)
description = models.TextField()
file = models.FileField(upload_to='uploads/%Y/%m/%d/%H/%M/%S/')
Here is the view:
def calendar(request):
events = CalendarEvent.objects.exclude(start__lt=datetime.datetime.now()).order_by('start')
return render_to_response('home/calendar.html',{'events': events},context_instance=RequestContext(request))
def download_handler(request, pk):
upload = get_object_or_404(CalendarEvent, pk=pk)
return serve_file(request, upload.file, save_as=True)
Here is my admin:
class calendarAdmin(admin.ModelAdmin):
list_display = ('title','start','end')
admin.site.register(CalendarEvent, calendarAdmin)
Finally, here is the relevant part of my template:
{% for e in events %}
{% url Calendar.views.download_handler pk=e.pk as fallback_url %}
Download
{% endfor %}
{% firstof e.file|public_download_url fallback_url %} is just returning blank, i'm not sure where I am going wrong.

The GAE blob store does not support public download according to the documentation here, so if you use the default backend for public download urls, it returns None. So my guess is that e.file|public_download_url always return None. You could verify that.
Then I think your template is wrong. You're trying to access e.views.download_handler where it should be Calendar.views.download_handler if your app is named Calendar.
I think the sample on the django-filetransfers page is error prone because the variable used in the template loop has the same name as the sample app: "upload".
If this doesn't fix it, could you post your urls.py from Calendar app. It could be that the template's url method is not able to resolve the url for Calendar.views.download_handler if there is no mapping in urlpatterns.
You should have something like
urlpatterns = patterns('Calendar.views',
...
(r'^download/(?P<pk>.+)$', 'download_handler'),
...
)
in this file.

I don't see anything special, eg
Download File
should work, or just use e.file.url directly?

I haven't deployed on Google App Engine myself, but this appears to be what django-filetransfers was designed for:
http://www.allbuttonspressed.com/projects/django-filetransfers#handling-downloads
edit: I believe I've answered this in the other question you posted, then: Trouble downlaoding file using Django FileTransfers

I think easiest way is to write a view since this file blob cannot be retrieved directly to write a function which is such:
def file_transfer(req, calendar_event_id):
try:
ce = CalendarEvent.objects.get(calendar_event_id)
except CalendarEvent.DoesNotExist:
raise Http404()
file = ce.file (Write Google appengine specfic routine to pull file)
return HttpResponse(file, media_type='file content type')
Hook it up on urls.py

Related

Integrating Wagtail pages into existing Django project

I build a website using Django and I need to add functionality to edit every peace of every page blocks on a site. I found Wagtail and read the docs about how to integrate it and thought of the way to integrate it via django views, like this (main is an app name):
main/pages.py:
...
class IndexPage(Page):
header_title = models.CharField(...)
header_subtitle = models.CharField(...)
...
main/views.py:
...
def view_index(request):
pages = Page.objects.all()
page = pages.filter(...) # somehow filter index page
return render(
request,
'index.html',
context={'page': page.specific},
content_type='text/html')
...
Is it good way to use Wagtail pages and integrate it into existing Django views this way? Could any surprises be found along the way?
Finally decided to use a StreamField. StreamField could be used to build a Page, like this:
main/pages.py:
class IndexPage(Page):
content = StreamField([
('title', blocks.CharBlock()),
('subtitle', blocks.CharBlock()),
...
])
IndexPage is a Model in Django terms (so we have a simple DB table) & content is stored like a list of JSON's. This two things gave our team an understanding to use it the way we want. To use it in a Django view this code could be used:
main/views.py:
...
def index_view(request):
page = IndexPage.objects.all().first()
return {
'content': unify(page.content),
}
unify - a special method to create a dict from content, because a content is an array where a title live inside content[0], subtitle - inside content[1], etc... Indices could be randomly rearranged, that's why unify is important to use. After unify have applied we can use a content in a template via attribute {{ content.title }}, {{ content.subtitle }}, etc...

Display a picture via Django saved on mysql database

I want to display a picture with Django, which is already saved on a mysql database. In all Methods I found people used models.Imagefield(upload_to='path'), but I think this will save the file into this directory and people from other computers won´t have access later.
So the question is, how do I access the database directly and display the picture without saving it in between?
I already managed to do this in python, but I am not quite sure how to implement the code into the models.py.
Something like this was my approach :
class mysqlpicture(models.Model):
#mysqlpic=something?
def openpic():
connection = pymysql.connect(user='root', passwd='***',
host='localhost',
database='db')
cursor = connection.cursor()
sql1='select * from Pictures'
cursor.execute(sql1)
data=cursor.fetchall()
mysqlpic=io.BytesIO(data[1][0])#one means second element of column zero
#img=Image.open(mysqlpic)
#img.show()
cursor.close()
return mysqlpic
and then I tried in the views.py to give mysqlpicdirectly to the httpresponse like this:
def MysqlView(request):
query_results = mysqlpicture.objects.all()
template = loader.get_template('polls/pic.html')
context = {
'query_results': query_results,
}
return HttpResponse(template.render(context, request))
using a template pic.htmlto insert a picture like:
{% for n in query_results %}
<mysqlpic src="{{ n.mysqlpic.url }}" />
{% endfor %}
Has someone an idea how to to this in the right way?
Yes, using ImageField does allow people from other computers to access it later. It inherits all attributes and methods from FileField which uploads the file into the server in the path specified in upload_to and also saves this path into your database to keep its reference. All of that happens when you call the save() method in your model instance.
Then, you can create the url to build a link by calling your_instance.image_field.url in your template. Also remember to have a look at MEDIA_ROOT and MEDIA_URL which respectively tells Django the server root path for saving your files and the url that handles the media served from MEDIA_ROOT.
You can use BinaryField for this purposes.
But as stated in the django documentation:
Although you might think about storing files in the database, consider that it is bad design in 99% of the cases.
from django.db import models
class MysqlPicture(models.Model):
mysqlpic = models.BinaryField()
# ...
And then to display in the template you can convert binary data to base64:
from base64 import b64encode
def mysql_view(request):
query_results = MysqlPicture.objects.all()
template = loader.get_template('polls/pic.html')
context = {
'images': [b64encode(obj.mysqlpic) for obj in query_results],
}
return HttpResponse(template.render(context, request))
Template:
{% for image in images %}
<img src="data:;base64,{{ image }}">
{% endfor %}

Redirection is leading me to Page not found error in Django

Project urls.py includes app urls. I am using HttpResponseRedirect to get Likes posted on site. I am not trying to call for template so this is why not using render_to_response. My app view is:
def like_article(request, article_id):
if article_id:
a = Article.objects.get(id=article_id)
count = a.likes
count += 1
a.likes = count
a.save()
return HttpResponseRedirect('articles/get/%s' % article_id)
My app urls.py reflects likes redirection like this:
url(r'^like/(?P<article_id>\d+)/$', 'article.views.like_article'),
My parent "articles" HTML file extended from base says:
<p>{{article.likes}} people liked this article</p>
My single article page extended from base.html shows:
<p>Like</p>
Please advise.
You'd better use {% url [name] [parameters] %} in your template while reverse function in your view to create urls.
In your question, I think the problem is the url router doesn't match.
See:
<p>Like</p>
And:
url(r'^like/(?P<article_id>\d+)/$', 'article.views.like_article'),
It seemed the /article prefix doesn't appeared in you url.
Have you mapped the url - articles/get/article_id, i.,e added a similar pattern in urlpatterns (ex: url(r'^get/(?P<article_id>\d+)/$', 'article.views.get_article', name='get_article'),) tuple, to which you redirected the users!
If yes, then have you created a proper view for it!

Allauth Facebook profile image not loading

I know this is a frequent issue, so pardon me for asking it again (it's really not a lack of research), I just can't seem to find a way to make Facebook Profile Picture load using Allauth.
I have used http://www.sarahhagstrom.com/2013/09/the-missing-django-allauth-tutorial/ for some tips, they all worked fine, but for Facebook Profile Picture seems to be missing something, the code on models.py responsible to pass the URL for Facebook Profile Picture can't get Facebook User Id
On the code below...
http://graph.facebook.com/{}/picture?width=40&height=40
... I've tried to use fb_uid and user_id but still doesn't load.
The profile URL is being called on the template as:
{% if request.user.is_authenticated %}
<img src="{{ request.user.profile.profile_image_url }}"/>
{% endif %}
Suggested here How can I get the user's facebook id with django-allauth? by Pennersr also doesn't give me access to users ID.
Thank you
The facebook api does not allow direct access to the image,You must write code to download the response from facebook profile url to your server and use your copy of the image.
The above code gives you URL which facebook redirects to their storage,so use
url = "http://graph.facebook.com/%s/picture?type=large" % response['id']
avatar = urlopen(url)
profile = user.get_profile()
profile.profile_photo.save(slugify(user.username + " social") + '.jpg',
ContentFile(avatar.read()))
profile.save()
But this approach is not recommended as it will cause delay in response,Some recommend celery background task to download the image,so look into that too.

Trouble downloading file using Django FileTransfers

I have am uploading a file through the admin section of my site that I would like to be able to be publicly downloaded through my website. I know that the file I have uploaded has been successfully uploaded because I can view it in the App Engine Blob storage. I am having trouble finding out what isn't working with the code below:
relevant part of my modeL:
class CalendarEvent (models.Model):
file = models.FileField(upload_to='uploads/%Y/%m/%d/%H/%M/%S/')
in my views.py file the relevant code is:
def calendar(request):
events = CalendarEvent.objects.exclude(start__lt=datetime.datetime.now()).order_by('start')
return render_to_response('home/calendar.html',{'events': events},context_instance=RequestContext(request))
def download_handler(request, pk):
upload = get_object_or_404(CalendarEvent, pk=pk)
return serve_file(request, upload.file, save_as=True)
in my template the relevant code is:
{% for e in events %}
{% url Calendar.views.download_handler pk=e.pk as fallback_url %}
Download
{% endfor %}
Your view name for your download_handler should be <appname>.views.download_handler. You probably don't have an app named "e" with an appropriate view in it.

Categories