I have a model like
class Document(models.Model):
comment = models.TextField(null=True,blank=True)
upload_date = models.DateTimeField(blank=False)
Document objects are listed in a template as
{% for doc in doc_list %}
{{ doc.comment }}
{{ doc.upload_date }}
{% endfor %}
However, I'd like to reach the properties of doc dynamically like
{{ doc."comment" }}
or
{{ doc|getField:"comment" }}
How can I do that?
Thanks
I assume you mean you want to access fields on a model by using another variable, which you don't necessarily know at the time. So you might have some_var be passed into the template, and this is the field in the model that you'd like to display, such as comment or upload_date.
You could build a template tag to do this:
#register.simple_tag
def get_model_attr(instance, key):
return getattr(instance, key)
Now in your template you can do stuff like:
{% for doc in doc_list %}
{% get_model_attr doc "comment" %}
{% get_model_attr doc some_var %}
{% endfor %}
Related
I have two very simple classes for products and photos. I would like to present products on the main page of my store along with photos related to a foreign key. But I do not know how to do this, I found many answers to get this in the view using a join like 'prefetch_related' but my ID changes for each case. So how do you present your photos for each product? are there any Django tags about which I do not know?
my models.py
class Product(models.Model)
name = models.CharField(max_length=10)
class Image(models.Model)
image = models.ImageField()
name_related = models.ForeignKay(Product, on_delate=models.CASCADE)
views.py
def home(request):
product_list = Product.objects.all()[:12]
#img = ??
context = {'product_list': product_list,
}
return render(request, 'home.html', context)
home.html
{% for product in product_list %}
{{ product.name }}
<!-- {{ product.imge }} ' element presenting the first photo for each 'product' model'???-->
{% endfor %}
Any help will be appreciated.
Since a foreign relation has been established you can iterate through the related models from the parent model.
The related models are already accessible from the parent model without doing anything explicit.
In your template you can do this:
{% for product in product_list %}
{{ product.name }}
{% for product_image in product.image.all %}
<!-- Iterate through this products related images -->
{{ product_image.image.url }}
{% endfor %}
{% endfor %}
For performance reasons, you will want to prefetch the relations, or else for every product you will do an additional query, so, in your view you will want to add this:
product_list = Product.objects.all().prefetch_related('image')[:12]
Just do
{% for product in product_list %}
{{ product.name }}
{% for image in product.image.all %}
<!-- {{ image.image.url }} -->?
{% endfor %}
{% endfor %}
I have the follow model:
class UserProfile(...):
...
photo1 = models.URLField()
photo2 = models.URLField()
photo3 = models.URLField()
photo4 = models.URLField()
photo5 = models.URLField()
And in the Create/Update template, I have to write five copies of the following div for file1 to file5:
<div>
Photo 1:
{% if userProfileForm.instance.file1 %}
<a href="{{ userProfileForm.instance.file1 }}" target=_blank>View</a>
{% endif %}
<input type=file name=file1>
{% if userProfileForm.instance.file1 %}
Delete
{% endif %}
</div>
Is there a way to iterate field file<i>?
{% for i in '12345' %}
<div>
Photo {{ forloop.counter }}:
...
</div>
{% endfor %}
in django you have _meta API. So I think this solves your problem if you use get_fields method (and maybe you will filter desired fields out).
hope it helps.
update with example
let me show how you should solve your problem:
desired_fields = []
for field in UserProfile._meta.get_fields()
if "photo" in field.name:
desired_fields.append(field.name)
context.update(fields=desired_fields) # pass it in the context
at this point you have your desired fields which should be used with for loop in the template. And one more thing, you would need to add some template tag to get real field from string representation:
# custom template tag
def from_string_to_field(instance, field_str):
return getattr(instance, field_str, None)
and in the template code will look like this
{% for field in fields %}
{{userProfileForm.instance|from_string_to_field:"field"}}
{% endfor %}
I am trying to get access to the instances of a ModelChoiceField to render them the way I want in a template by displaying several fields of the instances.
class MyForm(forms.Form):
mychoices = forms.ModelChoiceField(
queryset=ObjectA.objects.all(), widget=forms.RadioSelect(), empty_label=None
)
This does not work:
{% for choice in form.mychoices %}
{{ choice.pk}}
{% endfor %}
I also tried to use the queryset but it does not render anything
{% for choice in form.mychoices.queryset %}
{{ choice.pk}}
{% endfor %}
Any idea?
Thanks
{% for choice in form.mychoices.field.queryset %}
{{ choice.pk }}
{% endfor %}
Notice the extra .field. It's a bit strange the first time you come across it, but it gives you what you want. You can also access the choices attribute of that object, instead of accessing queryset directly, but you'll need to access the first element of the choice to get the PK of the instance, like this:
{% for choice in form.mychoices.field.choices %}
{{ choice.0 }}
{% endfor %}
I'd like to filter an object in Django, and return it along with any objects for which the results are a ForeignKey. I'm not sure if annotation is what I need here, or something else.
This is my model:
class Dress(models.Model):
name = models.CharField(...)
price = models.FloatField(...)
class ClothingSize(models.Model):
code = models.CharField(...)
class DressSizeAvailable(models.Model):
dress = models.ForeignKey(Dress)
size = models.ForeignKey(ClothingSize)
Say I want to filter all dresses under $50, and then display them with the available sizes. What is the best way to do this?
I've got as far as this:
# In view
results = Dress.objects.filter(price__lt=50)
# How to annotate with available sizes?
# In template
{% for result in results %}
{{ result.name }}, ${{ result.price }}
Sizes: {{ ??? }}
{% endfor %}
### 1st solution (similar to Daniel Rosenthal's answer but with performances concern)
results = DressSizeAvailable.objects.filter(dress__price__lt=50).select_related('dress', 'size')
# then you can browse your DressSizeAvailables as you wish in your template. The select related allows you NOT TO query the database again when you generate your template
### 2nd solution
results = Dress.objects.filter(price__lt=50).prefetch_related('dresssizeavailable_set__dress')
{% for dress in results %}
{{ dress.name }}, ${{ dress }}
Sizes: <ul>
{% for dsa in dress.dresssizeavailable_set %}
<!-- Thanks to the prefetch_related, we do not query the base again here -->
<li>{{ dsa.size.code }}</li>
{% endfor %}
</ul>
{% endfor %}
You'll need to give your template a queryset (or something similar) of DressSizeAvailable objects. So first you'll need to get all the Dress objects you're interested, and then filter DressSizeAvailable based on those Dresses
so in your view:
dresses = Dress.objects.filter(price__lt=50)
dress_size_available = []
for dress in dresses:
available = DressSizeAvailable.objects.filter(dress=dress)
dress_size_available.append(available)
Then render your template, passing it the variable dress_size_available
Your template can then be rather simple.
{% for dsa in dress_size_available %}
{{ dsa.dress.name }}, ${{ dsa.dress.price }}
Size: {{ dsa.size }}
{% endfor %}
I have a object that I'm trying to iterate over within my template.
My issue is that one of the fields response contains json data and I get this error message
transaction' object is not iterable
{% for item in transaction %}
{{ item.notjson_fields}}
{% for jsonItem in item.response %}
{{jsonItem}}
{% endfor %}
{% endfor %}
Model:
date_created = models.DateTimeField(auto_now_add=True)
request = JSONField()
response = JSONField()
You are trying to iterate over a Transaction object which is not iterable.
Try something like
{{ transaction.notjson_fields}}
{% for jsonItem in transaction.response %}
{{ jsonItem }}
{% endfor %}
I can't be sure though without knowing what Transaction looks like
Edit:
Since response is a JSONField, you can access it like a dict. Just do
{{ transaction.response.amount }}
If like Ngenator said, your field is not a JSON object but a string, you may need to load it first. First register a new template tag
from django import template
register = template.Library()
import json
#register.filter
def load_json(value):
return json.loads(value)
Then to get (just) the amount in your template
{% with transaction.response|load_json as jsondict %}
{% for k, v in jsondict.items %}
{% if k == "amount" %}
<td>{{ v }}</td>
{% endif %}
{% endfor %}
{% endwith %}
Good Luck.