Display django Model fields in a table - django

I have Model with 30+ fields and I want to display about 20 of them in a table. I know that there is {{ form.as_table }} but is there a comparable function for non-form models? I am currently using
{% for name, value in article.get_fields %}
<tr>
{% if value %}
<td>{{ name }} = {{ value }}</td>
{% endif %}
</tr>
{% endfor %}
-where get_fields returns all the fields of Article. This works fine. I would guess that there is a built-in django function for doing the same thing, but I can't find it in the documentation.

I agree with #kathikr, there isn't a function built in to the model class to do this for you.
One option would be to subclass Model and add a as_table() function to it that parsed available fields and used an exclude attribute where necessary.
def as_table(self):
return "".join(["<tr><td>%s</td><td>%s</td></tr>" % (field.verbose_name, field.value_to_string(self)) for field in self._meta.fields if field not in self.exclude])
hmm, this probable shouldn't be a one-liner
def as_table(self):
result = ""
for field in self._meta.fields:
if field not in self.exclude:
result += "<tr><td>%s</td><td>%s</td></tr>" %
(field.verbose_name, field.value_to_string(self))
return result

Related

Access Model attribute depending on URL parameter in Django

Is it possible to dinamically change a variable name in template?
In the view below I am sending to the template an url parameter called sl.
is it possible to pass that sl to the {{ devize.sl{{sl}} }} so that it changes dinamicaly ?
thank you
#login_required
def slList(request,centrudecost,SL):
queryset = Deviz.objects.filter(centrudecost_id=centrudecost)
sl = SL
print(centrudecost)
return render(request, "proiecte/sl_list.html", {"queryset": queryset,"sl":sl})
{% for devize in queryset %}
<td>{{ devize.sl{{sl}} }}</td>
{% endfor %}
You can not change the template variable dynamically but there is a workaround on the query side. You can create (annotate) a field (my_field) and fill it dynamically in the query:
field = "xyz_fieldname" # in your case field = "sl" + SL
queryset = Deviz.objects.annotate(my_field=F(field)).values('my_field',...).filter(centrudecost_id=centrudecost)
print(centrudecost)
return render(request, "proiecte/sl_list.html", {"queryset": queryset})
and in the template:
{% for devize in queryset %}
<td>{{ devize.my_field }} }}</td>
{% endfor %}

django dynamic template link dictonary to object fields

I am working on a dynamic template and i hoped to be able to include the last part of it aswell. My problem: I got a x-amount of fields that relate to fields of the object. But when i pass another model object it should show other fields.
Example:
model 1 show object name, category, approved
model 2 show object name, attribute,
For the other variable things, i make a dictionary that holds the information, problem is, i dont know how i could link the object fields to it.
Dictonary send to template:
field_map = {'field1': 'Name', 'field2': 'Category', 'field3': 'Approved'}
Template:
{% if objects|length > 0 %}
<table style="padding: 3px;">
<tr style=" text-align: center;">
{% for key, value in field_map %}
<th>{{ value }}</th>
{% endfor %}
</tr>
{% for object in objects %}
<tr>
<td>{{ object.name }}</td>
<td>{{ object.category }}</td>
<td>{{ object.approved }}</td>
</tr>
But now i want to add the objects fields to the field_map fields.
Cause i will be sending more then 1 object
Hope i explained my question well enough.
Can someone help me out?
You are trying to re-implmenet an already solved problem. Please use django-tables2 to render tables in django: https://github.com/bradleyayers/django-tables2
Update: To answer OP's comment on how to remove or edit the pagination footer:
If you do not want to have pagination to your table then just configure your table passing paginate=None to your RequestConfig like this:
table = TestTable(Test.objects.all())
RequestConfig(request, paginate=None).configure(table)
return render(request, 'test.html', {'table': table})
If you want to edit the footer yourself then you have to provide a new table rendering template. To do this, you just need to copy the contents of table.html from here https://github.com/bradleyayers/django-tables2/blob/master/django_tables2/templates/django_tables2/table.html to your templates directory. You can then modify this file to your requirements, for instance the pagination section is between {% if table.page %} and the {% endif %} at the end of the file.
Now, after you've created your custom table template you need render your table using this template. If you named your template as mytable.html then just use the following syntax from within your normal templates:
{% render_table mytable "mytable.html" %}

Display name of many to many relation in template

I try to display the names of fields from a Model in my template.
This works fine with any type of fields except ManyToManyField.
I use this function in my models.py to return all fields.
def get_all_fields(self):
"""Returns a list of all field names on the instance."""
fields = []
# only display fields with values and skip some fields entirely
if f.editable and value and f.name not in ('id','lastname','firstname') :
fields.append(
{
'label':f.verbose_name,
'name':f.name,
'value':value,
})
return fields
In my template I use this loop to display all fields:
{% for f in modelname.get_all_fields %}
<td>{{f.label|capfirst}}</td><td>{{f.value|escape|urlize|linebreaks}}</td>
{% endfor %}
As mentioned before, this works fine with all fields except ManyToManyFields.
For example one of my M2M relations looks like this:
family = models.ManyToManyField('family', related_name="family", null=True, blank=True)
I'd be thankful for every hint that helps solving this.
Regards
Conrad
Try to specify verbose_name argument for ManytoManyfield
family = models.ManyToManyField('family',verbose_name=u'trampampam', related_name="family", null=True, blank=True)
You write {{f.value|escape|urlize|linebreaks}}, which displays the value of the field. However, the value of a M2M relation is a set of object instances and you need to iterate again over the set (if that is the result you want):
{% load m2m_filter %}
{% for f in modelname.get_all_fields %}
<td>{{f.label|capfirst}}</td>
<td>
{% if f.value|is_m2m %}
{% for object in f.value.objects.all %}
{{ object|escape|urlize|linebreaks }}
{% endfor %}
{% else %}
{{f.value|escape|urlize|linebreaks}}
{% endif %}
</td>
{% endfor %}
and you also have to create the filter
m2m_filter.py
from django import template
from django.db import models
register = template.Library()
def is_m2m(value):
return type(value) == models.ManyToManyField *
register.filter('is_m2m', is_m2m)
* I guess, it's a different type; just check that

model form factory not displaying correctly

I am using model form set. If i use formset_factory then its displaying the form like this which is correct but if i use modelformset_factory then its displaying all the objects from model like this . It should be. Am I missing something? thanks
form
class MyImageForm(ModelForm):
class Meta:
model = MyImage
exclude = ('test', 'user')
MyImageFormSet = modelformset_factory(MyImage, MyImageForm)
template
{% for form in formset %}
{{ form.non_field_errors }}
<tr>
<td>{{ form.image }}</td>
<td></td>
</tr>
{% endfor %}
{{ formset.management_form }}
According to the Django documentation on modelformset, you can create MyImageFormSet as you have been doing, but simply filter it afterwards (and presumably return the new modelformset).
Create the modelformset as normal:
MyImageFormSet = modelformset_factory(MyImage, MyImageForm)
But use the modelformset with an empty query, like this:
MyImageFormSet(queryset=MyImage.objects.none())

Why are read-only form fields in Django a bad idea?

I've been looking for a way to create a read-only form field and every article I've found on the subject comes with a statement that "this is a bad idea". Now for an individual form, I can understand that there are other ways to solve the problem, but using a read only form field in a modelformset seems like a completely natural idea.
Consider a teacher grade book application where the teacher would like to be able to enter all the students' (note the plural students) grades with a single SUBMIT. A modelformset could iterate over all the student-grades in such a way that the student name is read-only and the grade is the editable field. I like the power and convenience of the error checking and error reporting you get with a modelformset but leaving the student name editable in such a formset is crazy.
Since the expert django consensus is that read-only form fields are a bad idea, I was wondering what the standard django best practice is for the example student-grade example above?
The reason you don't want to do this is because someone can change your disabled field to enabled and then submit the form. You would have to change the save function as to not insert the "disabled" data.
The standard way to do this is to not put the name in an input, but to display it as text
<form>
<div>
<label>Name</label>
<p>Johnny Five</p>
</div>
<div>
....
This is not possible in django.
I say if you really trust your userbase to not "mess" with things then go for it, but if its a public facing website with possible sensitive data then stay away.
As far as I can see for your situation, this is the ideal answer:
https://stackoverflow.com/a/2242468/1004781
Ie, simply print the model variables in the template:
{{ form.instance.LastName }}
When using a disabled field, you also need to make sure it remains populated correctly if the form fails validation. Here's my method, which also takes care of malicious attempts to change the data submitted:
class MyForm(forms.Form):
MY_VALUE = 'SOMETHING'
myfield = forms.CharField(
initial=MY_VALUE,
widget=forms.TextInput(attrs={'disabled': 'disabled'})
def __init__(self, *args, **kwargs):
# If the form has been submitted, populate the disabled field
if 'data' in kwargs:
data = kwargs['data'].copy()
self.prefix = kwargs.get('prefix')
data[self.add_prefix('myfield')] = MY_VALUE
kwargs['data'] = data
super(MyForm, self).__init__(*args, **kwargs)
for student/grading example, I have come up with a solution, where students are non editable fields and grades can be edited and updated as required. something like this
I am combining students objects and formset for grades in grade_edit class in view.py using zip function.
def grade_edit(request, id):
student = student.objects.get(id=id)
grades = grades.objects.filter(studentId=id)
gradeformset = GradeFormSet(request.POST or None)
if request.POST:
gradeformset = GradeFormSet(request.POST, request.FILES, instance=student)
if gradeformset.is_valid():
gradeformset.save()
grades = grades.objects.filter(studentId=id)
return render(request, 'grade_details.html', {'student': student, 'grades': grades})
else:
gradeformset = GradeFormSet(instance=student)
grades = grades.objects.filter(studentId=id)
zips = zip(grades, gradeformset)
return render(request, 'grade_edit.html', {'zips': zips, 'student': student, 'gradeformset': gradeformset })
My template looks something like this
<table>
<tr>
{% for field in gradeformset.forms.0 %}
{% if not field.is_hidden %}
<th>{{ field.label }}</th>
{% endif %}
{% endfor %}
</tr>
{% for f in gradeformset.management_form %}
{{ f }}
{% endfor %}
{% for student, gradeform in zips %}
<tr>
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
<td> {{ student.name }} </td>
<td> {{ gradeform.gradeA }} </td>
<td> {{ gradeform.gradeB }} </td>
</tr>
{% endfor %}
</table>
You can read more about Django formset here
http://whoisnicoleharris.com/2015/01/06/implementing-django-formsets.html