Okay so I have a homepage that displays images. This is accessed from my images tables. It contains a column of the owner, in the form of a user id. I also have a table of users, who've submitted those images. How do I make it so that when displaying images, it uses the ID to get the username from the user table?
views.py:
def index(request):
context = {}
populateContext(request, context)
context.update(gallery=ImageDoc.objects.only('thumbfile').order_by('-id'))
return render(request, 'register/index.html', context)
So in the index.html page, I can iterate through 'gallery' to show the images. Like so:
{% for image in gallery %}
<a href="/logo/{{ image.slug }}">
<img src="{{ MEDIA_URL }}{{ image.largethumbfile }}">
{{ image.title }} by {{ image.username }} for {{ image.price }}
</a>
{% endfor %}
"image.username" obviously doesn't work. I know I need to access the users table with this:
get_users = User.objects.get()
And reformat grabbing the images data to this:
get_images = ImageDoc.objects.get()
But I don't know the next step to ensure the data matches. Any ideas? Thank you!
If the Images table has the Users table as a foreign key, then each Images object will have a user_id parameter. Therefore, if you have a value called given_user_id you can do something like:
Images.objects.get(user_id=given_user_id)
If you have a username instead of a user_id, you can do something like:
Images.objects.get(user=User.objects.get(username=username))
Unfortunately, you cannot perform queries inside of a template block. You'll need to do any querying before you pass in your context object to the render function.
Related
I want to access the elements of a list using Jinja.
Here in the below code both "id" and images are list.
image_name is the field that stores the image
{% for blog in id%}
<h3>{{blog.news_title}}</h3><br/>
<img src="images[loop.index0].image_name"/><br/>
<time>{{blog.news_date}}</time><br/>
click here<br/>
{% endfor%}</li>
Views.py
def BlogViews(request,blog_type):
"""
The blogs are displayed according to the latest, current-month and last-month classification
"""
blog_type=blog_type.replace('-','_')
response_blog=requests.get("API" % (settings.BASE_URL,blog_type),headers=headers,verify=False)
if(response_blog.status_code==200):
data_blog=response_blog.json()
if(data_blog['ErrorCode']==0 and data_blog['SubErrorCode']==0):
blog=BlogYearViews()
blog_images=BlogImages(request,data_blog)
return render(request,"CombinedBlog.html",{"id":data_blog['Data'],"years":blog,"images":blog_images})
else:
return render(request,"Page404.html")
def BlogImages(request,data_blog):
"""
Returns a list of all the images
"""
data_image_list=[]
for i in range(0,len(data_blog['Data'])):
images=data_blog['Data'][i]['image_id']
response_image=requests.get("API"%(settings.BASE_URL),headers=headers,verify=False)
data_image=(response_image.json())
data_image_list=data_image_list+data_image['Data']
return (data_image_list)
You need to zip the two lists together in your view and iterate through them in the template.
blog_images = BlogImages(request, data_blog)
blogs_and_images = zip(data_blog['Data'], blog_images)
return render(request, "CombinedBlog.html", {"blogs_and_images": blogs_and_images, "years":blog})
...
{% for blog, image in blogs_and_images %}
<h3>{{ blog.news_title }}</h3><br/>
<img src="{{ image.image_name }}"/><br/>
<time>{{ blog.news_date }}</time><br/>
click here<br/>
{% endfor %}</li>
Note, you really should be using the {% url %} tag to create the hrefs rather than building it manually like that. Also note, your BlogImages function doesn't need to take the request, since it never uses it, and is anyway extremely un-Pythonic. It should look like this:
def blog_images(data_blog):
data_image_list = []
for blog in data_blog['Data']:
image_id = blog['image_id']
response_image = requests.get("API" % settings.BASE_URL, headers=headers, verify=False)
data_image = response_image.json()
data_image_list.append(data_image['Data'])
return
data_image_list
To access images list using index you can use forloop.counter.
You can use either:
{{ forloop.counter }} # index starts at 1
{{ forloop.counter0 }} # index starts at 0.
In template, you can do:
<img src="{{images[forloop.counter0].image_name.url}}"/>
Advice:
You should consider renaming blog lists as blogs or blog_list inplace of id.
I have data in a database in the form like this:
collection_name|manufacturer|product_type|description|image_url
----------------------------------------------------------------
Testing |FakeCo |Bed |pretty nice|/img/1.jpg
Testing |FakeCo |Desk |pretty bad |/img/2.jpg
Testing |FakeCo |Nightstand |pretty ok |/img/1.jpg
Testing |FakeCo |Draws |pretty nice|/img/3.jpg
Initially, I was using a for loop to display fields from each result, which ends up with something like this:.
For the example data set above, what I am trying to do is display only the first result from certain fields, knowing they are identical for all rows returned, and then for remaining fields only display them when they are distinct.
I tried using sets in my django view, as another answer suggested this would eliminate duplicates and solve my issue.
My django view:
def collection_detail(request, name=None):
template = loader.get_template('/webapps/my_webapp/furniture_site/main_page/templates/main_page/product-detail.html')
products = product.objects.filter(collection_name=name)
collection_name = []
manufacturer = []
description = []
image_url = []
for product in products:
collection_name.append(product.collection_name)
manufacturer.append(product.manufacturer)
description.append(product.description)
image_url.append(product.image_url)
collection_name = set(collection_name)
manufacturer = set(manufacturer)
description = set(description)
image_url = set(image_url)
context={'products': products}
return HttpResponse(template.render(context))
My issue is, that I am unable to refer to these set items in my template.
For example, in my template using:
{% for instance in products %}
{{ instance.collection_name }} Collection <br />
{% endfor %}
returns nothing, as does
{% for instance in products %}
{{ collection_name }} Collection <br />
{% endfor %}
What is the correct way to refer to items returned via the view in the template?
Ultimately, I am trying to get a result like the following (note descrption and collection name only used once, and duplicate image urls not returned).
First of all, you're not passing the right data towards your template.
You need to pass on collection_name, manufacturer, description and image_url in your context.
context = {
'products': products,
'collection_name': collection_name,
'manufacturer': manufacturer,
'description': description,
'image_url': image_url
}
Now you can access these in your template like:
{% for instance in collection_name %}
{{ instance }} Collection <br />
{% endfor %}
Same for the others.
It should render only one object in the loop. Still you can use first in your interpolation.
Like this:
{{ instance.collection_name|first }}
EDIT
You need to pass collection_name as you have initialised it as an empty list therefore it is a variable which you can use only when you pass it in context.
context={'products': products, 'collection_name': collection_name}
I'm overriding the wagtail AbstractFormField panel attribute in the following way:
...
before_input = RichTextField(verbose_name=_('before input'), blank=True)
after_input = RichTextField(verbose_name=_('after input'), blank=True)
panels = [
FieldPanel('label'),
FieldPanel('before_input'),
FieldPanel('after_input'),
FieldPanel('required'),
FieldPanel('field_type', classname="formbuilder-type"),
FieldPanel('choices', classname="formbuilder-choices"),
FieldPanel('default_value', classname="formbuilder-default"),
]
where the other panels are what comes out of the box.
This is working perfectly on the admin side and also saving as rich text into my database
I am pulling this through to my form in my template in the following way:
<form action="{% pageurl page %}" method="POST" class="lm-ls1" id="feedback-form">
{% csrf_token %}
{{ form.question1.help_text }} <!-- Simpler non interable way -->
{{ form.question1.before_input }}
<p>---------------</p>
{% for row in form.fields.values %}
{{row.choices}}
<p>---------------</p>
{{row.help_text}}
<p>---------------</p>
{{row.before_input}}
{% endfor %}
</form>
But I am only getting html output for the form panels excluding the before_input and after_input ones
I am getting through roughly the following:
Overall, how did you feel about the service you received today?
---------------
[('Very satisfied', 'Very satisfied'), ('Satisfied', 'Satisfied'),
('Neither satisfied nor dissatisfied', 'Neither satisfied nor dissatisfied'), ('Dissatisfied', 'Dissatisfied'), ('Very dissatisfied', 'Very dissatisfied')]
---------------
Overall, how did you feel about the service you received today?
---------------
---------------
How can I access the before_input field panel data stored in the _formfield wagtail table?
Bit late but hopefully this still helps you or someone else out there.
How Wagtail Forms Work
Wagtail forms provided to the view context for AbstractFormPage models is a fully instanced Django Form. This means that you will only ever find values in the form that can be given to a Django Form.
This includes fields, which are instances of Django's Fields (eg. CharField) and there is no simple way to add additional attributes to these fields.
You can see how the Form object is built in the Wagtail FormBuilder class definition.
1 - Make a Custom Template Tag
A somewhat simple way to get additional attributes on your FormField (Wagtail's FormField) is using a template tag.
Create a new file in in a folder templatetags in your app, and build a simple_tag that will take the form_page, the field (which will be a Django Field instance) and a string of the attribute name you want to get.
# myapp/templatetags/form_tags.py
from django import template
from django.utils.html import mark_safe
register = template.Library()
#register.simple_tag(name='form_field_attribute')
def form_field_attribute(form_page, field, attribute_name, default=None):
"""Return attribute on FormField where field matches 'field' provided."""
# field is a django Field instance
field_name = field.name
results = [
# if html is stored, need to use mark_safe - be careful though.
mark_safe(getattr(form_field, attribute_name, default))
# get_form_fields() is a built in function on AbstractFormPage
for form_field in form_page.get_form_fields()
# clean_name is property on AbstractFormField used for Django Field name
if form_field.clean_name == field_name]
if results:
return results[0]
return default
2 - Revise your form_page.html Template
In your template, cycle through your form (this is the Django Form instance) and use the template helper to get you the extra attributes you need. Example below, passing in page or self will work the same as they are both the instance of your FormPage.
<form action="{% pageurl page %}" method="POST" role="form">
{% csrf_token %}
{% for field in form %}
<div>{% form_field_attribute page field 'before_input' %}</div>
{{ field }}
<div>{% form_field_attribute page field 'after_input' %}</div>
{% endfor %}
<input type="submit">
</form>
In all code snippets I see basic pattern of how filter is applied to an URL. For example,
<img src="{{obj.url|filter}}" />
I wonder how can I use filter with URL that consists of two parts?
<img src="{{something}}{{obj.url}}" />
Note: filter should deal with the complete URL, not just the second part of it
EDIT:
Model:
class Foo(models.Model):
token = models.CharField(max_length=150)
reference = models.ForeignKey(Reference)
View:
def index(request):
foos = Foo.objects.filter(reference=value).all()
return render(request, 'index.html', {'foos' : foos})
Template:
{% for foo in foos %}
<img id="foo_{{foo.pk}}" src="{{MEDIA_URL}}{{foo.token}}" />
{% endfor %}
As a matter of fact, I want to just apply easythumbnail URL filter to image URL, which has two parts.
If you're wanting to do things with context variables like this then you should make what you require available in the context rather than trying to manipulate things in the template.
Either add variable from your view or create a context processor if you have variables that you require in lots of places, because through a context processor you can create variables that are always available.
Check out this answer I wrote recently on this; https://stackoverflow.com/a/27797061/1199464
update following your comment
There's nothing wrong with writing a method on your model to format a string or similar;
class Foo(models.Model):
token = models.CharField(max_length=150)
reference = models.ForeignKey(Reference)
def get_url(self):
url = u'{media_url}{path}'.format(
media_url=settings.MEDIA_URL,
path=self.token
)
return url
Template:
{% for foo in foos %}
<img id="foo_{{ foo.pk }}" src="{{ foo.get_url }}" />
{% endfor %}
And on a sidenote if you're not too familiar with Django yet, you should use MEDIA_URL for user uploaded content and STATIC_URL for content that is yours. You can read more on these here; How can I get the MEDIA_URL from within a Django template?
Django docs; https://docs.djangoproject.com/en/1.7/ref/settings/#media-url
I am using couchdb-python with Django. I am looking for a way to display an image (which is stored in the database as an attachment to a document) in a template. Oddly, I cannot find any example online of how to do this.
Currently, in the views.py I have something like this:
def displaypage(request,id):
docs = SERVER['docs']
try:
doc = docs[id]
except ResourceNotFound:
raise Http404
...
attachments = doc['_attachments']['someimage.jpg']
...
text_marked_down = markdown.markdown(doc['text'])
return render_to_response('couch_docs/display.html',{'row':doc,'attachments':attachments,'doctext':text_marked_down,...},context_instance=RequestContext(request))
Then, in the template display.html:
{% extends 'site_base.html' %}
{% block wrapper %}
{{ attachments }}
<div>{{ doctext|safe }}</div>
{{ endblock }}
I am seeing the text just fine, but for the image I only see the following:
{u'stub':True, u'length':27018,u'revpos':19,u'content_type': u'image/jpeg'}
So, clearly I am not passing the actual image, or not displaying it correctly anyway. Oddly, I cannot find an example online anywhere of how to actually do this. Can anyone point me to one, or provide it here?
You are using the template engine to render an HTML document. That document will be interpreted by the web browser just like any other HTML document.
Think about how an HTML page contains an image. The image is never inline within the HTML document itself. The HTML page contains a reference to instruct the browser to separately load the image and display it in place.
<img src="/path/to/image" />
So, likewise, you will need to:
create a separate view that will only return the binary data of the image. Set the mime type appropriately. See http://effbot.org/zone/django-pil.htm for some ideas how to return an image, but in your case set the contents of the response to be your image content.
add an <img ...> tag to your template that calls the new view you created.
once you drill down your db, you might want to consider building the url of each documents attachment as follows:
def function():
couch = couchdb.Server() #connect to server
db = couch['img'] #connect to database which contains docs with img attachments
doc_id = [] #create list of id's
http_docid = [] #create list to populate href for picture path
for i in db: #for each id in the db
doc_id.append(i) #add to the carid list
doc = db[i] #get the document id
for key in (doc['_attachments']): #for the key in the doc '_attacments' payload
print key #just to confirm
href_docid.append(('http://yourdbDomain/dbname/'+i+'/'+key)) #create a uri and append to a list
return href_docid
And below im using Jinja2's templating:
{% for img in function() %}
<img class="some-class" src="{{ img }}">
{% endfor %}
Hope this proves usefull!