I'm trying to render elements in a Django view. Every clinic object has many specialities, but for estetic reasons I only want the first three of them to be displayed in the template. I've tried:
def clinics_index(request):
clinics = Clinic.objects.all()
for clinic in clinics:
speciality = clinic.get_speciality_display
context = {
'clinics' : clinics,
'speciality' : speciality,
}
return render(request, 'guide/clinic/clinic_directory.html', context)
This now renders the human-readable name of the speciality field (which is a multiple choice field in the model). However, I can't use substraction to only get 3 elements like here:
speciality = clinic.get_speciality_display[:3]
As I get the following error:
TypeError at /guide/clinics/
'method' object is not subscriptable
How can I render it?
Edit:
This is the Clinic model:
class Clinic(models.Model):
name = models.CharField(max_length=75, blank=True, null=True)
speciality = MultiSelectField(choices=Speciality.choices, max_length=100, blank=True, null=True)
city = models.CharField(max_length=20, choices=Cities.choices, blank=True, null=True)
ward = models.CharField(max_length=20, choices=Wards.choices, blank=True, null=True)
full_address = models.CharField(max_length=100, blank=True, null=True)
maps_link = models.CharField(max_length=75, blank=True, null=True)
train_access = models.CharField(max_length=50, blank=True, null=True)
bus_access = models.CharField(max_length=50, blank=True, null=True)
parking = models.CharField(_('Parking availability'), max_length=75, blank=True, null=True)
phone_number = models.CharField(max_length=20, blank=True, null=True)
english_support = models.BooleanField(default=False, blank=True, null=True)
holiday_availability = models.BooleanField(_('Availability on weekends/holidays'), default=False, blank=True, null=True)
slug = models.SlugField(blank=True, null=True)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('guide:clinic_detail', kwargs={"slug" : self.slug})
And the template snippet:
<tbody>
{% for clinic in clinics %}
<tr>
<td>{{clinic.name}}</td>
<td>{{clinic.city}}</td>
<td>{{clinic.ward}}</td>
<td>{{speciality}}</td>
<td><a href="{{clinic.get_absolute_url}}">More...</a></td>
</tr>
{% endfor %}
</tbody>
EDIT:
This code is rendering the first 3 human readable elements as I wanted:
clinics = Clinic.objects.all()
for clinic in clinics:
speciality = ','.join(clinic.get_speciality_display().split(',')[:3])
However, I am struggling to render it correctly with its correspondant instance. This code:
fff = [{'name': i.name, 'speciality': ','.join(i.speciality[:3])} for i in Clinic.objects.all()]
Is rendering the non-human readable names. How could connect both (and also display city
and ward
fields for each instance)?
I assume that in a loop you want to collect all the data. To do this, you need to save them to a list. But that's overkill, just pass clinics
to a dictionary and iterate over all the values in the template. Also, for links, I used clinic.slug
instead of clinic.get_absolute_url
, since the model already returns the generated url through the get_absolute_url
method.
views.py
def clinics_index(request):
clinics = Clinic.objects.all()[:3]
return render(request, 'guide/clinic/clinic_directory.html', {'context': clinics})
templates
{% for clinic in context %}
<p>{{ clinic }}</p>
<tr>
<td>{{ clinic.name }}</td>
<td>{{ clinic.city }}</td>
<td>{{ clinic.ward }}</td>
<td>{{ clinic.speciality }}</td>
<td><a href="{{ clinic.slug }}">More...</a></td>
</tr>
{% endfor %}
</tbody>
Update 05.11.2022 To get the clinic.get_speciality_display() value, you need to call the method using parentheses. When I print out the value type, I get a string. Therefore, in order to take the first three elements, I turn the string into a list, select the desired number and again turn it into a string.
So you can select the first three records:
clinics = Clinic.objects.all()
for clinic in clinics:
speciality = ','.join(clinic.get_speciality_display().split(',')[:3])
all code: views.py
def clinics_index(request):
#fff = [{'name': i.name, 'speciality': i.speciality[:3]} for i in Clinic.objects.all()]#if you need to display 'speciality' as a list
fff = [{'name': i.name, 'speciality': ','.join(i.speciality[:3])} for i in Clinic.objects.all()]
return render(request, 'guide/clinic/clinic_directory.html', {'context': fff})
templates
<tbody>
{% for a in context %}
<tr>
<p><td>{{ a.name }}</td></p>
<p><td>{{ a.speciality }}</td></p>
</tr>
{% endfor %}
</tbody>
If that's not what you need. Show what the data looks like and what you want to see.