Django-Provide a download from a function defined in a model - django

I am trying to implement a view, where a logged in user that has uploaded a file can download his file, but only his, not other users files, so I don't create an id url based on the pk of the file . As a result in the views I query the test_result_file table and I filter it for a specific user. I think that I can do what I want by writing a function in my model:
class test_result_file(models.Model):
user=models.ForeignKey(User)
system=models.ForeignKey(system)
test_id=models.ForeignKey(Detail)
path=models.CharField(max_length=300)
class Meta:
verbose_name="Test Result file"
verbose_name_plural="Test Result files"
def get_self(self):
path=self.path
wrapper = FileWrapper(open( path, "r" ))
response=HttpResponse(wrapper, content_type="text/plain")
response['Content-Disposition'] ='attachment; filename="results.txt"'
return response
However, in the template, when I call:
<ul>
{% for at in attempts %}
<li>System Name: <em>"{{ at.system}}"</em>, download file: here </li>
{% endfor %}</ul>
the download is not provided and instead the browser tries to open a url with all the parameters of response and fails.
Am I losing something? Is this feasible with that function?

First point: a response is not an url. What you want in your template are urls, not responses. Second point: generating a reponse is the responsability of a view, not of a model. Side note : you should respect Python's coding conventions (cf pep08)
The RightWay(tm) to organize your code would be:
# myapp/models.py
class TestResultFile(models.Model):
user=models.ForeignKey(User)
system=models.ForeignKey(System)
test_id=models.ForeignKey(Detail)
path=models.CharField(max_length=300)
class Meta:
verbose_name="Test result file"
verbose_name_plural="Test result files"
# myapp/views.py
def download_file(request, file_id):
testfile = get_object_or_404(TestResultFile, pk=file_id)
wrapper = FileWrapper(open(testfile.path, "r" ))
response=HttpResponse(wrapper, content_type="text/plain")
response['Content-Disposition'] ='attachment; filename="results.txt"'
return response
# myapp/urls.py
urlpatterns = patterns('',
url(r'^download/(?P<file_id>\d+)/?', 'views.download_file', 'myapp_download_file'),
# ...
)
# myapp/templates/myapp/template.html
<ul>
{% for at in attempts %}
<li>
System Name: <em>"{{ at.system}}"</em>,
download file: here
</li>
{% endfor %}
</ul>

Maybe you can simply use somthing like this:
class userfile(model.Model):
user=models.ForeignKey(User)
file = models.FileField(_('file'), upload_to='userfile/', blank=False)
def __unicode__(self):
return "%s file" % user
and in you template:
{% if user.userfile_set.count > 0 %}
<ul>
{% for file in user.userfile_set.all %}
<li>File: {{file}} dowload it</li>
{% endfor %}
</ul>
{% else %}
You don't have any file
{% endif %}
I hop it can help you.

Related

How to select another array of data by subscript in a django for loop

I have a problem when transfering two list to a html in django.
I hope that it will be a:1b:2Each of two data is paired.
But it does not work. There have some demo codes, showing the same error.
Absolutly,it has no error log,because the {{l2s.order}} is null,and the system does not throw error.Maybe my poor English makes it confusing,If there are any where no description clearly, please point out, I'll add the appropriate information。
Thanks for your help.
# fake view
def test(request):
l1s = ["a","b","c","d","e","f"]
l2s = ["1","2","3","4","5","6"]
return render(request,'fake.html',locals())
# fake html
{% for l1 in l1s% }
{% with order=forloop.counter0 %}
{{l1}}-{{l2s.order}}
{% endfor %}
You can use the built in zip method for that
views.py
def test(request):
l1s = ["a","b","c","d","e","f"]
l2s = ["1","2","3","4","5","6"]
context['data'] = zip(l1s, l2s)
return render(request,'fake.html',context)
fake.html
{% for item in data %}
{{item[0]}} : {{ item[1] }}
{% endfor %}

Django: context of modified query list

I have a database with blog style documents, i.e., author's name, publication date, body text, etc.
I have built a django framework to output entries from the database as a result of a search term. That part is ok. The problem is that I want to show sections of the body text with the matched search terms highlighted (equivalent to a google search result). This means that I can't create a template tag with the body_text attribute only, because that text is not highlighted. I already did a function that receives as input the query and the body text and outputs the same text with the found search terms in bold.
My problem now is how do I pass this result to the html template?
Using the tutorial from Django documentation suppose you have the following views.py:
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
context = {'latest_question_list': latest_question_list}
return render(request, 'polls/index.html', context)
and the correspondent template:
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li>{{ question.question_text }}</li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
Now suppose you have the function in views.py:
def signal_tokens(text,query_q):
...
return new_text
What should be the best way to replace the {{ question.question_text } with the output from signal_tokens? My solution was to replicate the context variable with a list of dictionaries, where each dictionary is a copy of each entry, except for the 'question_text' key, where I used signal_tokens result:
def index(request):
query_q = 'test'
latest_question_list = Question.objects.order_by('-pub_date')[:5]
new_context = []
for entry in latest_question_list:
temp_d = {}
temp_d['id'] = entry.id
temp_d['question_text'] = signal_tokens(entry.question_text,query_q)
new_context.append(temp_d)
context = {'latest_question_list': new_context}
return render(request, 'polls/index.html', context)
But the problem is that I need to copy all entries. Is there a more elegant way to solve this problem?
This is an ideal use case for a template filter. Move your highlight code to a file in the templatetags directory, register it as a filter, then you can call it from the template:
{{ question.question_text|highlight:query_q }}
Obviously you will need to pass query_q to the template context as well.

How can I use django-jfu with a ImageField and a FK?

I'm trying to use django-jfu to multiupload images, but I have a problem. I want to handle a foreign key dynamically (via url or something), but I can't think of anything.
I have the following models:
class Event(models.Model):
name = models.CharField(max_length=128)
class Picture(models.Model):
event = models.ForeignKey(Event)
image = models.ImageField(upload_to='media')
According to django-jfu, you have to specify a "upload" view to call from the template via template tag. This is my upload view:
#require_POST
def upload(request):
event = Event.objects.get(id=26)
file = upload_receive(request)
instance = Picture(image = file, event = event)
print instance
instance.save()
basename = os.path.basename(instance.image.path)
file_dict = {
'name' : basename,
'size' : file.size,
'url': settings.MEDIA_URL + basename,
'thumbnailUrl': settings.MEDIA_URL + basename,
'deleteUrl': reverse('jfu_delete', kwargs = { 'pk': instance.pk }),
'deleteType': 'POST',
}
return UploadResponse(request, file_dict)
Right now, as a test, it only saves pictures to event with id=26, but how can I handle it dynamically? This is the view and template where I'm calling the template tag:
view
def add_pictures_to_event(request, event_id):
return render(request, 'add_pictures_to_event.html')
template
{% extends 'base.html' %}
{% load staticfiles %}
{% load jfutags %}
{% block body %}
<div class="container">
<h2>Photo upload</h2>
{% jfu %}
</div>
{% endblock %}
As you can see, the view add_pictures_to_event, gets the request and the id of the event, but I cant seem to pass it to the upload view.
Any help would be appreciated.
I had the same question. I looked at different django versions of jQuery File Upload but stuck with Alem's jfu but with the changes from Thomas Willson to make it work in 1.9. My solution might not be the best but I could not find an other way.
I assume you already created an event and then add images to it.
media_upload_form.html is in my projects static directory. I used the UPLOAD_FORM_EXTRA block to add a hidden formfield with the current event_id:
{% block UPLOAD_FORM_EXTRA %}
<input type="hidden" name="currentevent" value="{{instance.pk}}">
{% endblock %}
I assume you have the view from the docs. I changed in the beginning of the uploadview:
file = upload_receive( request )
event_instance = get_object_or_404(Event, id=request.POST['currentevent'])
instance = Picture( file = file, event=event_instance)
instance.save()
It is probably against all django rules but it works. If anyone has a better solution I like to know too. FormSets maybe?

Django The 'image' attribute has no file associated with it

When a user registers for my app.I receive this error when he reaches the profile page.
The 'image' attribute has no file associated with it.
Exception Type: ValueError
Error during template rendering
In template C:\o\mysite\pet\templates\profile.html, error at line 6
1 <h4>My Profile</h4>
2
3 {% if person %}
4 <ul>
5 <li>Name: {{ person.name }}</li>
6 <br><img src="{{ person.image.url }}">
Traceback Switch back to interactive view
File "C:\o\mysite\pet\views.py" in Profile
71. return render(request,'profile.html',{'board':board ,'person':person})
I think this error happens because my template requires a image and seen he just registered he can't add a image unless he go to the edit page and adds a page then he can access the profile page.
My profile.html
<h4>My Profile</h4>
{% if person %}
<ul>
<li>Name: {{ person.name }}</li>
<br><img src="{{ person.image.url }}">
</ul>
{% endif %}
My Profile function at views.py
def Profile(request):
if not request.user.is_authenticated():
return HttpResponseRedirect(reverse('world:LoginRequest'))
board = Board.objects.filter(user=request.user)
person = Person.objects.get(user=request.user)
return render(request,'profile.html',{'board':board ,'person':person})
I tried this solution by creating a 2 instance of Person object and separating them at my template with a if but it didn't succeed.
<h4>My Profile</h4>
{% if person %}
<ul>
<li>Name: {{ person.name }}</li>
</ul>
{% endif %}
{% if bob %}
<ul>
<br><img src="{{ bob.image.url }}">
</ul>
My solutions to the Profile function
def Profile(request):
if not request.user.is_authenticated():
return HttpResponseRedirect(reverse('world:LoginRequest'))
board = Board.objects.filter(user=request.user)
person = Person.objects.get(user=request.user)
bob = Person.objects.get(user=request.user)
return render(request,'profile.html',{'board':board ,'person':person,'bob':bob})
I'm been reading the documentation for Built-in template tags and filters I think a solution here is to use ( and ) template tag but I can't seem to use it properly.
How can I configure this template to make picture an option. If their are no picture leave it but display the persons name.
Thank you for helping me
bob and person are the same object,
person = Person.objects.get(user=request.user)
bob = Person.objects.get(user=request.user)
So you can use just person for it.
In your template, check image exist or not first,
{% if person.image %}
<img src="{{ person.image.url }}">
{% endif %}
The better approach which would not violate DRY is to add a helper method to the model class like:
#property
def image_url(self):
if self.image and hasattr(self.image, 'url'):
return self.image.url
and use default_if_none template filter to provide default url:
<img src="{{ object.image_url|default_if_none:'#' }}" />
My dear friend, others solvings are good but not enough because If user hasn't profile picture you should show default image easily (not need migration). So you can follow below steps:
Add this method to your person model:
#property
def get_photo_url(self):
if self.photo and hasattr(self.photo, 'url'):
return self.photo.url
else:
return "/static/images/user.jpg"
You can use any path (/media, /static etc.) but don't forget putting default user photo as user.jpg to your path.
And change your code in template like below:
<img src="{{ profile.get_photo_url }}" class="img-responsive thumbnail " alt="img">
Not exactly what OP was looking for, but another possible solution would be to set a default value for ImageField:
class Profile(models.Model):
# rest of the fields here
image = models.ImageField(
upload_to='profile_pics/',
default='profile_pics/default.jpg')
you have two choices :
first one:
in the model field try to put a default image value , like this :
PRF_image = models.ImageField(upload_to='profile_img', blank=True, null=True , default='profile_img/925667.jpg')
the second one (recommended) :
add a custom method inside your class model like the following , to return PRF_image url if exist or return empty string if not :
PRF_image = models.ImageField(upload_to='profile_img', blank=True, null=True )
#property
def my_PRF_image(self):
if self.PRF_image :
return self.PRF_image.url
return ''
and inside your template you can use :
{{ your_object.my_PRF_image }}
i hope this helpful .
You can also use the Python 3 built-in function getattr to create your new property:
#property
def image_url(self):
"""
Return self.photo.url if self.photo is not None,
'url' exist and has a value, else, return None.
"""
if self.image:
return getattr(self.photo, 'url', None)
return None
and use this property in your template:
<img src="{{ my_obj.image_url|default_if_none:'#' }}" />
Many way to solve this issue
Try below code
models.py # under Person class
#property
def imageURL(self):
if self.image:
return self.image.url
else:
return 'images/placeholder.png'
html file
<img src="{% static person.imageURL %}" class="thumbnail" />
Maybe this helps but my database didn't save on of the pictures for the object displayed on the page.
As that object in models.py has blank=False and also I am looping through object, it constantly gave an error until I added a replacement picture in the admin for the database to render.
This error also arises when any one or more items doesn't have an image added and the rest items do. To fix this:
class Product(models.Model):
pname = models.CharField(max_length=30)
price = models.IntegerField()
img = models.ImageField(null = True,blank = True)
def __str__(self):
return self.pname
#property
def imageURL(self):
try:
url = self.img.url
except:
url=''
return url
I had a similar problem , but my issue was with the form in HTML template. if you don't set the enctype = "multipart/form-data" attribute then it does not upload the image hence the reason for the error

Django: How can you get the current URL tagname (for pagination)?

I'm trying to do pagination with the page parameter in the URL (instead of the GET parameter). I also want my pagination to be shared code across multiple different templates.
Given that, I think I need to do something like this :
urls.py:
url(r'^alias/page;(?P<page>[0-9]+)/(?P<id>.*)$', alias.get, name="alias"),
tempaltes/alias.html:
<div>...stuff...</div>
{% include "paginator.html" %}
templates/paginator.html :
{% if page_obj.has_previous or page_obj.has_next %}
{% load filters %}
<div class="pagination clear">
{% if page_obj.has_previous %}
‹‹ previous
...
What is somemagic?
Assume I want to keep my url the same except set the page page_obj.previous_page_number
Edit:
You need somemagic to be a variable with the name of the current view.
Try this:
{% with request.path_info|resolve_url_name as current_view %}
{% url current_view page_obj.previous_page_number object.id %}
{% endwith %}
You can get this working with some code from django-snippets:
Variable resolving URL template tag Makes the {% url %} tag resolve variables from context.
Resolve URLs to view name The function resolve_to_name(path) returns the view name for path. You just need to create a filter that uses this function.
This solution wont work with urls like:
'alias/param1_regexp/param2_regexp/page;(?P<page>[0-9]+)/(?P<id>.*)$'
because you've no clue about param1 and param2.
A modification can be done to the django-snippets above to make this kind of urls work:
First snippet modifications:
from django.template import defaulttags, VariableDoesNotExist, Variable
class ResolvingURLNode(defaulttags.URLNode):
def render(self, context):
original_view_name = self.view_name
try:
resolved = Variable(self.view_name).resolve(context)
if len(resolved) > 1:
self.view_name = resolved[0]
if resolved[1]:
self.args = [Variable(arg) for arg in resolved[1]]
elif len(resolved) > 0:
self.view_name = resolved[0]
else:
self.view_name = resolved
except VariableDoesNotExist:
pass
ret = super(defaulttags.URLNode, self).render(context)
# restore view_name in case this node is reused (e.g in a loop) in
# which case the variable might resolve to something else in the next iteration)
self.view_name = original_view_name
return ret
defaulttags.URLNode = ResolvingURLNode
Second snippet modifications
from django.core.urlresolvers import RegexURLResolver, RegexURLPattern, Resolver404, get_resolver
__all__ = ('resolve_to_name',)
def _pattern_resolve_to_name(self, path):
match = self.regex.search(path)
if match:
name = ""
if self.name:
name = self.name
elif hasattr(self, '_callback_str'):
name = self._callback_str
else:
name = "%s.%s" % (self.callback.__module__, self.callback.func_name)
if len(match.groups()) > 0:
groups = match.groups()
else:
groups = None
return name, groups
def _resolver_resolve_to_name(self, path):
tried = []
match = self.regex.search(path)
if match:
new_path = path[match.end():]
for pattern in self.url_patterns:
try:
resolved = pattern.resolve_to_name(new_path)
if resolved:
name, groups = resolved
else:
name = None
except Resolver404, e:
tried.extend([(pattern.regex.pattern + ' ' + t) for t in e.args[0 ['tried']])
else:
if name:
return name, groups
tried.append(pattern.regex.pattern)
raise Resolver404, {'tried': tried, 'path': new_path}
# here goes monkeypatching
RegexURLPattern.resolve_to_name = _pattern_resolve_to_name
RegexURLResolver.resolve_to_name = _resolver_resolve_to_name
def resolve_to_name(path, urlconf=None):
return get_resolver(urlconf).resolve_to_name(path)
Basically, resolve_to_name returns the name of the view and it's parameters as a tuple, and the new {% url myvar %} takes this tuple and uses it to reverse the path with the view name and it's parameters.
If you don't like the filter approach it can also be done with a custom middleware.
Previous answer
You should check django-pagination, it's a really nice django application, easy tu use and gets the job done.
With django pagination the code to paginate an iterable would be:
{% load pagination_tags %}
{% autopaginate myiterable 10 %} <!-- 10 elements per page -->
{% for item in myiterable %}
RENDERING CONTENT
{% endfor %}
{% paginate %} <!-- this renders the links to navigate through the pages -->
myiterable can be anything that is iterable:list, tuple, queryset, etc
The project page at googlecode:
http://code.google.com/p/django-pagination/
It will be something like the following. Except I don't know what you mean by id so I just put a generic object id. The syntax for url is {% url view_name param1 param2 ... %}
{% url alias page_obj.previous_page_number object.id %}
Updated base on your need:
{% url alias page_obj.previous_page_number object.id as prev_url %}
{% include "paginator.html" %}
...
{% if page_obj.has_previous %}
‹‹ previous