Django Aggragate query issue in template - python

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.

Related

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 %}

Django: Check that row exists in list

I want to check that user_id exists in the profile_images table from my Django template.
My Model
class profiles(models.Model):
profile_id = models.AutoField(primary_key=True)
user = models.ForeignKey(User)
-----
class Profile_images(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(User)
image = models.ImageField(upload_to='uploads/',default = 'uploads/no-img.jpg')
My View
def view_profiles(request):
if request.user.is_authenticated():
view_all_profiles = profiles.objects.all()
profile_image = Profile_images.objects.all()
return render_to_response('profiles/all.html', {'profiles':view_all_profiles,'profile_image':profile_image}, context_instance=RequestContext(request),)
else:
return HttpResponseRedirect('/accounts/login/')
My Template
{% for profile in profiles %}
<li>
{% for image in profile_image %}
{% ifequal image.user_id profile.user_id %}
<img src="{{MEDIA_URL}}{{image.image}}" alt="image" />
{% endifequal %}
<!-- i want to check here if not user_id exist in profile_images table -->
{% if profile.user_id not in profile_image %}
<img src="{% static 'images/no-image.jpg' %}" alt="image" />
{% endif %}
{% endfor %}
</li>
{% endfor %}
{% if profile.user_id not in profile_image %} is not working. I'm new to Django & python and I'm stuck here. Please suggest better ways if my code is not correct.
in your view you could get all user_ids with a profile image, something like:
user_ids_with_profile_images = Profile_images.objects.all().values_list('user_id', flat=True)
Then in your template you could check if profile.user_id not in user_ids_with_profile_images.
It might actually be a little cleaner to loop through all the users with profiles in your system and get their profile images through the foreign key, instead of looping through all the profiles and trying to get the users...
This is really a design problem, you've got a separate model specifically for a profile image when that could just be a field on the profile model itself.
class Profile(models.Model): # convention is to use a non-plural name for models
# No need to explicitly set the primary key, this will be added automatically
# profile_id = models.AutoField(primary_key=True)
user = models.ForeignKey(User)
image = models.ImageField(upload_to='uploads/',default = 'uploads/no-img.jpg')
-----
Now it would just be a case of using {{ profile.image }} with no need for any additional looking up.

django categories: How to get children of a category using django-categories?

I am using django-categories to implement music related app. I want artist as my category and his/her songs as children
models.py
from django.db import models
from django_extensions.db.fields import AutoSlugField
from categories.models import CategoryBase
class Artist(CategoryBase):
cat = models.CharField(max_length=255, blank=True)
def __unicode__(self):
return self.name
class Song(models.Model):
title = models.CharField(max_length=255,)
slug = AutoSlugField(populate_from='title', unique=True)
description = models.TextField()
cat = models.ForeignKey(Artist, blank=True)
def __unicode__(self):
return self.title
In templates, artist_details.html
{% extends 'base_post.html' %}
{% load category_tags %}
{% block page_content %}
<h1>{{ artist.name }}</h1>
{% if artist.children.count %}
<h2>Subcategories</h2>
<ul>
{% for child in artist.children.all %}
<li>{{ child }}</li>
{% endfor %}
</ul>
{% endif %}
The template is getting rendered coz I can see artist's name. But i am unable to fetch the children. I checked the docs but I could not find much stuff related to fetching children.
There is data for both models in my DB, I added relevant info via admin interface. Can anyone tell me what I am missing ?
Also I open to using better packages. You can give any suggestions that implements categories.
SOLUTION: From django docs https://docs.djangoproject.com/en/1.6/topics/templates/#accessing-method-calls
thanks mariodev
Even using django-categories, you can't have songs as children of artists. Artists just do not form a category.
What you instead want is something like this:
from django.db import models
from django_extensions.db.fields import AutoSlugField
from categories.models import CategoryBase
class MusicCategory(CategoryBase):
# add extra fields, like images, "featured" and such here
pass
class Artist(CategoryBase):
name = CharField(max_length=255,)
categories = models.ManyToManyField(MusicCategory, related_name="artists")
def __unicode__(self):
return self.name
class Song(models.Model):
slug = AutoSlugField(populate_from='title', unique=True)
title = models.CharField(max_length=255,)
artist = models.ForeignKey(Artist, related_name="songs", on_delete=models.PROTECT)
categories = models.ManyToManyField(MusicCategory, related_name="songs")
description = models.TextField()
def __unicode__(self):
return self.title
and with some templates
{% extends 'base_post.html' %}
{% load category_tags %}
{% block page_content %}
<h1>{{ artist.name }}</h1>
{% if artist.songs.all.exists %}
<h2>Songs</h2>
<ul>
{% for song in artist.songs.all %}
<li>{{ song }}</li>
{% endfor %}
</ul>
{% endif %}
REF: https://django-categories.readthedocs.org/en/latest/custom_categories.html#creating-custom-categories

Django foreign key relation in template

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 %}

Categories