Django foreign key relation in template - python

i know you will say that this question is asked before many times but i havent solved it yet...
models.py
class Doc(UploadModel):
doc_no = models.CharField(max_length=100, verbose_name = "No", blank=True)
date_added = models.DateTimeField(verbose_name="Date", default=datetime.now,
editable=False)
class DocImage(models.Model):
property = models.ForeignKey(Doc, related_name='images')
image = FileBrowseField("Docs", max_length=200,
directory="doc_img/%Y/%m/%d/%H/%M/%S/",
extensions=[".jpg",".tif"], blank=True, null=True)
views.py
def doc_detail(request, dosc_no):
res = Doc.objects.filter(doc_no = dosc_no)
return render_to_response("doc/doc_detail.html", {"result": res})
templates:
{% for i in docimage.property_set.all %}
{{ i.image.url }}
{% endfor %}
i have tried above template but i didnt get any result. so i want to get imageurl adress in DocImage class...
all helps

If you review the foreign key documentation, if you have a relationship like
Doc -> has many DocImages
you need to define your foreign key on the DocImages class like so:
class DocImage(models.Model):
property = models.ForeignKey(Doc, related_name='images')
If you don't set related names, you can access the DocImages from the Doc like:
Doc.docimage_set.all()
Docs on Related Objects
But setting related_name in the property field lets you do
Doc.images.all()
Just make sure whatever you pass to the template in the view context matches what is used in the template, e.g.
# in the view
return render_to_response('mytemplate.html', { 'mydoc' : doc, 'mydocimage' : img }
This can then be used in the template as follows:
# and in your template to get the images attached to the document
{% for i in mydoc.images.all %}
...
{% endfor %}
# or to get the document the image belongs to
{{ mydocimage.property.date_added }}

first you iterate over the result
the images related to a Doc are retrieved by the images property of doc which is generated from the related_name attribute in the ForeignKey
code:
{% for doc in result %}
{% for docimage in doc.images.all %}
{{ docimage.image.url }}
{% endfor %}
{% endfor %}

Related

How do you get queryset objects related to queryset passed to templates in Django

I have these two models and as you can see they have a relationship.
class Post(models.Model):
text = models.TextField()
class PostImage(models.Model):
post = models.ForeignKey(Post, default=None, on_delete=models.CASCADE)
image = models.FileField(upload_to = 'media/',blank=True, null=True)
As far as I understand if I query posts and push them to a template and post, I would expect to use something like this in my templates to retrieve the images URL attached to the posts but it doesn't seem to work.
{% for post in posts %}
{% for post_image in post.post_image_set.all %}
{{post_image.image.url}}
{% endfor %}
{% endfor %}
What am I doing wrong?
Here is my views.py file.
views.py
# Create your views here.
def index(request):
posts=Post.objects.filter(approved=True).order_by('-published_date')
context = {"posts":posts}
return render(request, 'post/home.html',context)
The default related name for a foreign key relational is the name of the model (PostImage) but in your template for loop you called it post_image Following relationships “backward”
change
{% for post_image in post.post_image_set.all %}
into
{% for post_image in post.postimage_set.all %}
Template code (with change)
{% for post in posts %}
{% for post_image in post.postimage_set.all %}
{{post_image.image.url}}
{% endfor %}
{% endfor %}

Django - Forms - assign custom attributes to forms in forms.py

The question title might be a little misleading, but I couldn't think of a better title. If you've got better title, please edit the title.
I have following set of models.py and forms.py`
# models.py
class BHA_Component(models.Model):
field_1 = models.CharField(max_length=100)
field_2 = models.CharField(max_length=100)
field_3 = models.CharField(max_length=100)
# forms.py
class BHA_Component_Form(forms.ModelForm):
class Meta():
fields = '__all__'
I want to create custom attributes for each field, so that I can identify what kind of field it is on the Front-End, and assign a class for each field type.
Something like this:
Some fields are just plain blank, some are grey, some are purple, and some have check boxes. These are done by manually giving each field a particular HTML class on the Front-End. However, I want to give each field some attributes on the Back-End, and have those attributes identified on the Front-End. So, something like this:
{% for field in bha_component_form %}
{% if field.custom_attribute == 'option_1' %}
{{ field|add_class:"has_checkbox"}}
{% else if field.custom_attribute == 'option_2' %}
{{ field|add_class:"blue_background"}}
{% else %}
{{ field|add_class:"plain"}}
{% endif %}
{% endfor %}
How can I do this?
To pass in attributes on the backend you can try something likes this:
email = forms.EmailField(widget=forms.EmailInput(attrs={'class': "form_control form-control-lg", 'placeholder': "Email"}), required=True, )
So, for your specific case:
models.py:
class BHA_Component(models.Model):
field_1 = models.CharField(max_length=100, widget=forms.TextInput(attrs={'custom_attribute': "option_1") })
field_2 = models.CharField(max_length=100, widget=forms.TextInput(attrs={'custom_attribute': "option_2") })
field_3 = models.CharField(max_length=100, widget=forms.TextInput() })
It should be a case of using something like this in your template:
{% for field in bha_component_form %}
{% if field.widget.attrs.custom_attribute == 'option_1' %}
{{ field|add_class:"has_checkbox"}}
{% else if field.widget.attrs.custom_attribute == 'option_2' %}
{{ field|add_class:"blue_background"}}
{% else %}
{{ field|add_class:"plain"}}
{% endif %}
{% endfor %}
It should just be a case of modifying what I have outlined above for your specific use case.
Hope that helps!

Django Template - show many-to-many relationship

I'm learning Django after having built some basic apps in Flask. One thing I want to do is show users a list of all posts and whether or not they follow that given post. However, Jinja or Django is throwing some error that I don't quite know how to debug.
Models.py
class User(models.Model):
id = models.AutoField(primary_key=True)
username = models.CharField(unique=True, max_length=120,blank=False)
password = models.CharField(max_length=120, blank=True, null=False)
class Record(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=120, unique=True, blank=True)
followers = models.ManyToManyField(User, through='Follow')
class Follow(models.Model):
id = models.AutoField(primary_key=True)
record = models.ForeignKey(Record)
user = models.ForeignKey(User)
date_followed = models.DateField(null=True, blank=True)
records.html
{% for i in records %}
{% if i.follow.filter(id='1').first() %}
DO SOMETHING
{% endif %}
{% endfor %}
error
TemplateSyntaxError at /records/
Could not parse the remainder: '(id='1').first()' from 'i.follow.filter(id='1').first()'
To test this out when I run the python manage.py shell and execute the following I have no issues:
>>> x = Record.objects.first()
>>> x.followers.filter(id='1').first()
<User: User object>
I had initially prototyped this app using Flask and had the following jinja template and never had an issue:
{% for i in accounts %}
{% if i.follow.filter_by(user_id='1').first() %}
DO SOMETHING
{% endif %}
{% endfor %}
You cannot do that logic in template. You can create a method in Record model that does it for you and you can call it in template
class Record(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=120, unique=True, blank=True)
followers = models.ManyToManyField(User, through='Follow')
def first_follower(self):
if self.follow_set.filter(user_id=1).exists():
return True
return False
and in template:
{% for i in records %}
{% if i.first_follower %}
DO SOMETHING
{% endif %}
{% endfor %}
This is by design https://code.djangoproject.com/ticket/1199
The idea is that a django template should focus on design, for designers, and let the more complex code run in Python, not when the template renders.
So if this is a single instance when you use this check, add it to the view:
def get_context_data(self,*arg,**kwargs):
context = super(MyRecordView,self).get_context_data(*args,**kwargs)
context[has_follow] = self.object.follow.filter_by(user_id='1').exists()
return context
In the template:
{% if has_follow %}
...
{% endif %}
However, if you use this check a lot, you can add it to your model:
def has_follow(self):
return self.follow.filter_by(user_id='1').exists()
And then you can access it in a template, w/o any changes to the view context, since it's a model attribute:
{% if i.has_follow %}
...
{% endif %}

Related Objects Reference Django

Given the following code:
Models.py
class Advertisement(models.Model):
title = models.CharField(null=True, blank=True, max_length=30)
created_by = models.ForeignKey(User)
class Gallery(models.Model):
advertisement = models.ForeignKey(Advertisement, related_name='images')
image = models.ImageField(upload_to=image_directory_path, help_text="Your ad image (Recommended size: 1024x768)")
creation_date = models.DateTimeField(editable=False, default=timezone.now)
Views.py
def do_foo(request):
search_result = Advertisement.objects.all().order_by('-creation_date')
return render(request, 'content_search.html',
{
'search_result': search_result
})
page.html
{% for ad in search_result %}
{% for ad_image in ad.gallery_set %}
<img src="{{ ad_image.image.url }}">
{% endfor %}
{% endfor %}
How do I access the backwards relation between Advertisement and Gallery? I tried ad.gallery_set and ad.images_set but I could not get the images.
I tried to follow what they say here Django Relation Objects Reference and in this topic.
Your code has related_name="images". So ad.images it is.
Edit: as shredding notes correctly, you can't use that directly if you want to loop over it, and need to add .all to get a queryset object:
{% for ad_image in ad.images.all %}
<img src="{{ ad_image.image.url }}">
{% endfor %}
Maybe related name "galleries" would be a bit more clear.

Django Aggragate query issue in template

Here's my code:
MODEL
class compilation (models.Model):
user = models.ForeignKey(User)
title = models.CharField(max_length=100, null=False, blank=False)
slot = models.PositiveIntegerField()
slotpergroup = models.PositiveIntegerField()
songs = models.ManyToManyField(song,related_name="slotsongs", null=True, blank=True)
class song(models.Model):
title = models.CharField(max_length=150)
content = models.FileField(upload_to='static/canzoni', validators=[validate_file_audio])
groups = models.ManyToManyField(group)
class group(models.Model):
user = models.ManyToManyField(User)
name = models.CharField(max_length=50)
genr = models.CharField(max_length=50)
avatar = models.FileField(upload_to='static/logogruppi', validators=[validate_file_extension])
VIEW
c = {}
compilation = compilation.objects.all()
c.update({'compilation': compilation })
return render_to_response('compilation.html', c, context_instance=RequestContext(request))
TEMPLATE compilation.html
{% for cd in compilation %}
{{ cd.title }}<br/>
PLAYLIST
{% for song in cd.songs.all %}
{{ song.title | capfirst }}<br/>
{% for g in song.groups.all %}
{{ g | capfirst }}
{% endfor %}
{% endfor %}
{% for gr in user.group_set.all %}
--> here my problem, I need something like this:
var = song.objects.filter(groups=gr).filter(slotsongs=cd).count()
if cd.slotpergropu <= var:
print: "all slots are busy for this group" <--
{% endfor %}
{% endfor %}
I need to show for each compilation, for each user's group, if there are available slots or if someone of his group took all own available slot yet.
Django enforces MVC framework by not implicitly allowing any Buseness logic in Templates.
By standards these kind of things should be done in Views and the result should be passed as context to Templates.
But, if it is so necessary to Make this query in the Templates then you can use Template tags for this purpose like following:
Use Assginment tag here:
{% load songs_tags %}
{% get_songs_for_group gr cd as var %}
Create template tag file
### templatetags/songs_tags.py ###
#register.assignment_tag
def get_songs_for_groups(group, collection):
return song.objects.filter(groups=group).filter(slotsongs=collection).count()
See documentation for more details: https://docs.djangoproject.com/en/dev/howto/custom-template-tags/#howto-custom-template-tags
Unfortunately, you can't call a function that requires parameters in a template. You have to assemble what you need in views.py, write a template tag or filter instead. Take a look at the documentation to learn more about it.

Categories