How does one go about editing the template(s) shown when using wagtail.contrib.modeladmin?
Assuming
class EventsAdmin(ModelAdmin):
menu_label = 'Events'
list_display = ('title',)
Say I want to make the titles clickable, how would I go about doing so?
I figured I could check the templates in wagtail/contrib/modeladmin/templates and add something like <a href="{{ url }}" /> alas the furthest I got to finding that title section was in wagtail/contrib/modeladmin/templates/modeladmin/includes/result_row_value.html where it outputs the title section through the {{ item }} tag
{% load i18n modeladmin_tags %}
{{ item }}{{ url }}{% if add_action_buttons %}
{% if action_buttons %}
<ul class="actions">
{% for button in action_buttons %}
<li>{% include 'modeladmin/includes/button.html' %}</li>
{% endfor %}
</ul>
{% endif %}
{{ closing_tag }}
{% endif %}
#modeladmin_tags.py
#register.inclusion_tag(
"modeladmin/includes/result_row_value.html", takes_context=True)
def result_row_value_display(context, index):
add_action_buttons = False
item = context['item']
closing_tag = mark_safe(item[-5:])
request = context['request']
model_admin = context['view'].model_admin
field_name = model_admin.get_list_display(request)[index]
if field_name == model_admin.get_list_display_add_buttons(request):
add_action_buttons = True
item = mark_safe(item[0:-5])
context.update({
'item': item,
'add_action_buttons': add_action_buttons,
'closing_tag': closing_tag,
})
return context
Going further I don't really understand how the <td> with the title are put in there nor what I can do to make it clickable or customise that template.
A screenshot to illustrate the UI section
I'm having trouble getting my form to save in Dajngo due to the following error on validation:
<ul class="errorlist"><li>pt_medical_condition<ul class="errorlist"><li>Select a valid choice.
['anx', 'Bip'] is not one of the available choices.
>pt_surgical_history<ul class="errorlist"><li>Select a valid choice.
['bre', 'pca'] is not one of the available choices.
I've got this model:
class pt_data(models.Model):
condition_choices = [('ane', 'Anemia'), ('anx', 'Anxiety'), ('art', 'Arthritis'),
('ast', 'Asthma'), ('Bip', 'Bipolar'), ('ca', 'Cancer'), ('clo', 'Clotting disorder'),
('chf', 'CHF'), ('mdd', 'Depression'), ('cop', 'COPD'), ('ger', 'GERD'),
('gla', 'Glaucome'), ('hiv', 'HIV/AIDS'), ('ibs', 'IBS/Crohn\'s'),
('hld', 'High cholesterol'), ('ckd', 'Kidney disease'), ('ner', 'Nerve/Muscle disease'),
('ocd', 'OCD'), ('ost', 'Osteoporosis'), ('pai', 'Pain disorder'), ('pts', 'PTSD'),
('sch', 'Schizophrenia'), ('sei', 'Seizures'), ('sca', 'Sickle cell anemia'),
('su', 'Substance use disorder'), ('thy', 'Thyroid disease')]
surgery_choices = [('app', 'Appendix removal'), ('bra', 'Brain surgery'),
('bre', 'Breast surgery'), ('cabg', 'CABG'), ('pca', 'Cardiac stent'),
('cho', 'Gallbladder removal'), ('col', 'Bowel surgery'), ('csec', 'C-section'),
('fra', 'Bone fracture repair'), ('her', 'Hernia repair'), ('hys', 'Uterus removal'),
('joi', 'Joint replacement'), ('lun', 'Lung surgery'), ('spi', 'Spine/back surgery'),
('thy', 'Thyroid surgery'), ('ton', 'Tonsil removal'), ('strf', 'Tubal ligation'),
('strm', 'Vasectomy'), ('wei', 'Weight reduction surgery')]
pt_medical_condition = models.CharField(max_length=100, blank=True, null=True,
choices=condition_choices)
pt_surgical_history = models.CharField(max_length=100, blank=True, null=True, choices=surgery_choices)
And this form:
class ptForm(forms.ModelForm):
class Meta:
model = pt_data
fields = ('__all__')
widgets = {
'pt_medical_condition': CheckboxSelectMultiple(attrs={'class': 'cond_checkbox'}),
'pt_surgical_history': CheckboxSelectMultiple(attrs={'class': 'surg_checkbox'}),
}
And this is my HTML:
{% for check in form.pt_medical_condition %}
{% if forloop.counter|divisibleby:3 %}
<div> </div>
{% endif %}
<label class='mx-2' id="{{ check.choice_label }}">
{{ check.tag }} {{ check.choice_label }}
</label>
{% endfor %}
{% for check in form.pt_surgical_history %}
{% if forloop.counter|divisibleby:2 %}
<div> </div>
{% endif %}
<label class='mx-2' id="{{ check.choice_label }}">
{{ check.tag }} {{ check.choice_label }}
</label>
{% endfor %}
The HTML is rendered just fine, the problem seems to arise on submit. It looks like the correct characters are there, however they are surrounded by incorrect characters. The following "anx" is appropriate but won't be validatated by Django because everything else that has been tacked on 'anx'. Could it be a problem with posting the information with AJAX? Or maybe using a CSRF cookie to POST? Has anyone else encountered this problem? Any suggestions would be helpful.
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 follow this previous question here:
Django: getting the list of related records for a list of objects
but can't seem to get it to work.
I get a list of owners but do not get a list of pet names. The html code doesn't seem to execute the 2nd FOR loop. Any ideas?
models.py
class Teacher(models.Model):
teacher = models.CharField(max_length=300, verbose_name="teacher")
def __unicode__(self):
return self.teacher
class Owner(models.Model):
relevantteacher = models.ForeignKey(Teacher, verbose_name="teacher")
owner = models.CharField(max_length=300, verbose_name="owner")
def __unicode__(self):
return self.owner
class PetName(models.Model):
relevantowner = models.ForeignKey(Owner, verbose_name="owner")
pet_name = models.CharField(max_length=50, verbose_name="pet Name")
def __unicode__(self):
return self.pet_name
views.py
def ownersandteachers(request):
owners = Owner.objects.all()
context = {'owners': owners}
return render(request, 'ownersandpets.html', context)
template
{% for i in owners %}
{{ i.owner }} has pets:<br />
{% for v in owners.petname_set.all %} //this doesn't seem to be executing
- {{ v.pet_name }}<br />
{% endfor %}
{% endfor %}
You are doing
{% for v in owners.petname_set.all %}
where you should be doing
{% for v in i.petname_set.all %}
owners is the queryset, but you need to get the petname_set for the individual object in the queryset which is i in this case.
Also, I would recommend a condition check if i.petname_set exists. If not, do not show the has pets: text.
{% for i in owners %}
{{ i.owner }}
{% if i.petname_set.count %} has pets:<br />
{% for v in i.petname_set.all %} //this doesn't seem to be executing
- {{ v.pet_name }}<br />
{% endfor %}
{% endif %}
{% endfor %}
I have a model called Subtopic. One of my templates runs a forloop on an object, returning a different field for each cell of a table row.
Two of the table cells look up a field which is a ManytoMany foreign key, both to the same foreign model, Resource. I want each to display different results, based on the value of a boolean field within the Resource model.
What you see below is currently working fine, but doesn't attempt to filter by the boolean field.
models.py:
class ICTResourceManager(models.Manager):
def get_query_set(self):
return super(ICTResourceManager, self).get_query_set().filter('is_ict': True)
class NonICTResourceManager(models.Manager):
def get_query_set(self):
return super(NonICTResourceManager, self).get_query_set().filter('is_ict': False)
class Resource(models.Model):
subtopics = models.ManyToManyField(Subtopic)
external_site = models.ForeignKey(ExternalSite)
link_address = models.URLField(max_length=200, unique=True, verify_exists=False)
requires_login = models.BooleanField()
is_ict = models.BooleanField()
flags = models.ManyToManyField(Flag, blank=True)
comment = models.TextField()
def __unicode__(self):
return u'%s %s' % (self.external_site, self.link_address)
objects = models.Manager()
ict_objects = ICTResourceManager()
nonict_objects = NonICTResourceManager()
class Meta:
ordering = ['external_site', 'link_address']
views.py:
def view_ks5topic(request, modulecode, topicshortname):
listofsubtopics = Subtopic.objects.filter(topic__module__code__iexact = modulecode, topic__shortname__iexact = topicshortname)
themodule = Module.objects.get(code__iexact = modulecode)
thetopic = Topic.objects.get(module__code__iexact = modulecode, shortname__iexact = topicshortname)
return render_to_response('topic_page.html', locals())
My template:
{% for whatever in listofsubtopics %}
<tr>
<td>
{{ whatever.objective_html|safe }}
<p>
{% if request.user.is_authenticated %}
{% with 'objective' as column %}
{% include "edit_text.html" %}
{% endwith %}
{% else %}
{% endif %}
</td>
<td>
{% regroup whatever.resource_set.all by external_site.name as resource_list %}
{% for external_site in resource_list %}
<h4>{{ external_site.grouper }}</h4>
<ul>
{% for item in external_site.list %}
<li>{{ item.comment }}</li>
{% endfor %}
</ul>
{% endfor %}
</td>
</tr>
{% endfor %}
As you can see, I've added extra managers to the model to do the filtering for me, but when I replace the appropriate lines in the template, I just get blanks. I have tried: for external_site.ict_objects in resource_list and for item.ict_objects in resource_list and <a href="{{ item.ict_objects.link_address }}">. If this were in the view I could probably do the filter just by .filter('is_ict': True), but with this being inside a forloop I don't know where to do the filtering.
I also tried writing regroup whatever.resource_set.filter('is_ict': True) in the template, but the syntax for regrouping seems to use resource_set.all rather than resource_set.all() (and I don't know why) so the filter text doesn't work here.
Turns out it was possible to do it using a custom template filter. The original efforts to filter within the template weren't working, given that as is well documented the template language is not a fully-fledged python environment. My original question remains open for anyone who knows an alternative method that more directly addresses the question I was originally asking, but here's how I did it:
myapp_extras.py:
from django import template
register = template.Library()
def ict(value, arg):
"filters on whether the is_ict Boolean is true"
return value.filter(is_ict=arg)
register.filter('ict', ict)
My template, note the use of the custom filter in line 2:
<td>
{% regroup whatever.resource_set.all|ict:1 by external_site.name as resource_list %}
{% for external_site in resource_list %}
<h4>{{ external_site.grouper }}</h4>
<ul>
{% for item in external_site.list %}
<li>{{ item.comment }}</li>
{% endfor %}
</ul>
{% endfor %}
</td>
After this I was able to remove the additional custom managers from the model.
One further question, when filtering for the boolean is_ict field, I found that I had to use filter(is_ict=1) and filter(is_ict=0). Is that the only way to refer to a True or False value?