I would like to display something like this in my template:
Name: John
Age: 18
City: New York
Using, for example, this code:
views.py
def person_details(request,pk):
person = get_object_or_404(Person, id=pk)
return render(request, 'template.html', {'person': person, 'person_fields': person._meta.get_fields()})
template.html
{% for field in person_fields %}
<div class="col-4 form-group">
<p><strong>{{ field.verbose_name }}:</strong> {{ person[ field.name ] }}</p>
</div>
{% endfor %}
Is this possible in python? I ask because I have a model that have about 20 fields and hard coding the fields in template would be a little hard.
You can use Django's to-python queryset serializer.
Just put the following code in your view:
from django.core import serializers
data = serializers.serialize( "python", SomeModel.objects.all() )
And then in the template:
{% for instance in data %}
{% for field, value in instance.fields.items %}
{{ field }}: {{ value }}
{% endfor %}
{% endfor %}
Its great advantage is the fact that it handles relation fields.
For the subset of fields try:
data = serializers.serialize('python', SomeModel.objects.all(), fields=('name','size'))
Django templates are deliberately restricted, such that writing business logic is hard (or close to impossible). One typically performs such logic in the model or view layer.
def person_details(request, pk):
person = get_object_or_404(Person, id=pk)
person_data = {
f.verbose_name: getattr(person, f.name, None)
for f in person._meta.get_fields()
}
return render(request, 'template.html', {'person': person, 'person_data': person_data })
and then render it with:
{% for ky, val in person_data.items %}
<div class="col-4 form-group">
<p><strong>{{ ky }}:</strong> {{ val }}</p>
</div>
{% endfor %}
It is however advisable not to do this serialization yourself, but to use other serialization methods like these listed in this answer.
Related
Good day,
I'm trying "create" a DatePicker for one of my Inputfields in Django but it's not working!
In my models.py:
class Customer(models.Model):
...
name = models.CharField()
date = models.DateField()
In my views.py:
def Page(request):
CustomerFormSet = modelformset_factory(Customer, fields='__all__')
formset = CustomerFormSet (queryset=Customer.objects.none())
...
context = {'formset': formset}
return render(request, 'app/base.html', context)
In my template:
{% extends 'app/base.html' %}
{% load widget_tweaks %}
<form actions="" method="POST">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
{{ form.id }}
...
{% render_field form.name class="form-control" %}
...
{% render_field form.date class="form-control" %}
...
Now my first Inputfield works fine! It returns a fitting Field in Bootstraps "Form-Group"-Layout. But my InputField for Dates remains a simple TextInput with no calendar apearing to choose from.
My Question is: am I doing something wrong or is it still impossible to obtain such a function in this way?
Thanks and a nice evening to all of you.
If you ara using ModelForm try:
from django import forms
class DateInput(forms.DateInput):
input_type = 'date'
class DataTreinoForm(forms.ModelForm):
class Meta:
model = models.YOURMODEL
fields = _all_
widgets = {
'dateField': DateInput
}
The default format is mm/dd/yyyy. I don't know how to change it in this way.
I just solved this too. Add type="date" to the render_field.
{% render_field form.date type="date" class="form-control" %}
You can add any input tag attributes here which is convenient because
Modify form appearance on the template instead of forms.py, which is conceptually consistent
When you save templates, it doesnt reload the app, so faster testing with html
I'm trying to develop a forum application.
I'm trying to display the latest topic that's been posted in each category on a listing page. However, I realised after adding more than one category that I need a separate query for each single category or it just shows the newest topic overall.
I'm just not sure how to keep my logic in the view for the queries. Obviously, I could just perform the query inside of my for loop but that doesn't seem very MVT oriented.
Here's my views.py:
from django.shortcuts import render
from .models import ForumReply, ForumCategory, ForumTopic
def index(req):
categories = ForumCategory.objects.all()
#find latest topic or topic by reply
topic = ForumTopic.objects.latest('created_at')
reply = ForumReply.objects.latest('created_at')
if (topic.created_at > reply.created_at):
latest = topic
else:
latest = reply.topic
return render(req, "forum/category_listing.html",
{'categories': categories, 'latest': latest})
And my category_listing.html:
{% extends '__base.html' %}
{% block content %}
{% for category in categories %}
<div class="forum_category">
<h1>{{ category.title }}</h1>
{{ category.body }}
<br />
<em>Latest Post: </em> {{ latest.title }} by {{ latest.user }} at {{ latest.created_at|date:"D d F Y h:i" }}
</div>
<br />
{% endfor %}
{% endblock %}
You can create a custom template tag that returns the latest post for each category.
Something like this:
# views.py
def index(req):
categories = ForumCategory.objects.all()
return render(req, "forum/category_listing.html", {'categories': categories})
# templatetags/category_tags.py
#register.assignment_tag
def get_latest_post(category):
# perform logic here for selecting latest post for specific category
return latest
# category_listing.html
{% load category_tags %}
{% for category in categories %}
{% get_latest_post category as latest %}
<em>Latest Post: </em> {{ latest.title }} by {{ latest.user }} at {{ latest.created_at|date:"D d F Y h:i" }}
{% endfor %}
You can read the documentation for more information https://docs.djangoproject.com/en/1.9/howto/custom-template-tags/#assignment-tags
I'm following a tutorial on effectivedjango.com, and this is the code they have:
views.py:
class CreateContactView(CreateView):
model = Contact
template_name = 'edit_contact.html'
fields = '__all__' #this is needed for error msg Using ModelFormMixin (base class of CreateContactView) without the 'fields' attribute is prohibited.
def get_success_url(self):
return reverse('contacts-list')
def get_context_data(self, **kwargs):
context = super(CreateContactView, self).get_context_data(**kwargs)
context['action'] = reverse('contacts-new')
return context
class UpdateContactView(UpdateView):
model = Contact
template_name = 'edit_contact.html'
fields = '__all__'
def get_success_url(self):
return reverse('contacts-list')
def get_context_data(self, **kwargs):
context = super(UpdateContactView, self).get_context_data(**kwargs)
context['action'] = reverse('contacts-edit', kwargs={'pk' : self.get_object().id})
return context
urls.py:
url(r'^$', contacts.views.ListContactView.as_view(),
name='contacts-list',),
url(r'^new$', contacts.views.CreateContactView.as_view(),
name='contacts-new',),
url(r'^edit/(?P<pk>\d+)/$', contacts.views.UpdateContactView.as_view(),
name='contacts-edit',),
contact_list.html:
{% block content %}
<h1>Contacts</h1>
<ul>
{% for contact in object_list %}
<li class="contact">
{{ contact }}
(edit)
</li>
{% endfor %}
</ul>
Add contact
{% endblock %}
edit_contact.html:
{% block content %}
{% if contact.id %}
<h1>Edit Contact</h1>
{% else %}
<h1>Add Contact</h1>
{% endif %}
<form action="{{ action }}" method="POST">
{% csrf_token %}
<ul>
{{ form.as_ul }}
</ul>
<input id="save_contact" type="submit" value="Save" />
</form>
Back to list
{% if contact.id %}
Delete
{% endif %}
{% endblock %}
Why does the line context['action'] = reverse('contacts-edit', kwargs={'pk' : self.get_object().id}) in views.py look like its calling itself?
What I mean is, this action is called when the submit button is pressed in the contact-edit template, correct? So it starts there, and it is reverse-calling contact-edit which is itself, right?
What am I not seeing here?
Thank you for all your help.
Yes, the line context['action'] = reverse('contacts-edit', kwargs={'pk' : self.get_object().id}) in views.py is calling itself. This line generates the proper url for contacts-edit view.
This is done so that POST requests come to the same view i.e. UpdateContactView which is an UpdateView. There, proper handling will be done i.e. form validation will occur with the sent data. If the form is valid, object will be updated. Otherwise, the form will be displayed again with errors.
Django docs on UpdateView:
A view that displays a form for editing an existing object,
redisplaying the form with validation errors (if there are any) and
saving changes to the object.
Please help me in displaying the values of dictionary in django templates. I tried google to find out, but could not get the solution.
Below is the Model
class Ride(models.Model):
type = models.BooleanField(default=False)
add_source = models.ForeignKey(Address, related_name='source')
add_destination = models.ForeignKey(Address, related_name='destination')
ride_comment = models.TextField(null=True,max_length=140,blank=True)
def __unicode__(self):
return self.ride_comment
class Driver(models.Model):
ride_id = models.ForeignKey(Ride)
user_id = models.ForeignKey(User)
drv_carseats = models.SmallIntegerField(null=True,blank=False)
def __unicode__(self):
return self.user_id.username
View
for ride in result_list:
if ride.type:
driver = Driver.objects.get(ride_id = ride)
userList[ride.pk] = driver.user_id.username
print 'driver', driver.user_id.username, userList[ride.pk]
return render_to_response('rides/search.html', {'result_list':result_list,'userList':userList}, context )
And here is my template code
{% for result in result_list %}
{% if result %}
{{ userList[result.pk] }}
<em>{{ result.add_source }}</em>
<em>{{ result.add_destination }}</em>
<em>{{ result.ride_comment }}</em>
{% endif %}
{% endfor %}
I am getting the following error
TemplateSyntaxError at /rides/search/
Could not parse the remainder: '[result.pk]' from 'userList[result.pk]'
you should write a django custom filter for this.
create a file name get_dict_val.py inside your app..
project
-app
-templatetags
__init__.py
get_dict_val.py
Now in get_dict_val.py
#register.filter
def get_item(dictionary, key):
return dictionary.get(key)
In template
add this as first line write..
{% load get_dict_val %}
now replace in your code in template
{{ userList|get_item:result.pk }}
You don't need to create dictionary to access drivers at the template level, you can follow the relationship backward as Driver model has the foreign key for Ride model:
{% for result in result_list %}
{% if result %}
{% with result.driver_set.all as drivers %}
{% for driver in drivers %}
{{ driver.user_id }}
{% endfor %}
{% endwith %}
<em>{{ result.add_source }}</em>
<em>{{ result.add_destination }}</em>
<em>{{ result.ride_comment }}</em>
{% endif %}
{% endfor %}
It is good to specify the related_name for ForeignKey as it makes life easier to access objects:
ride_id = models.ForeignKey(Ride, related_name='drivers')
Then you can do:
ride = Ride.objects.get(id='some_id')
drivers = ride.drivers.all()
I want to render form grouping fields. Form actually is created dynamically according to incoming dictionary
for f in settings.FORM_BIG_FIELDS:
self.fields[f['id']] = eval(f['type'])(label=f['label'], required=f.get('required', True))
self.fields[f['id']].groupp = f.get('group', 1)
groupp attribute means appropriate group, then I try to render it like
{% regroup form.fields.values by groupp as field_group %}
{% for group in field_group %}
<div class="group_{{ group.grouper }}">
{% for field in group.list %}
<p>
{{ field.all }}
{{ field }}
</p>
{% endfor %}
</div>
{% endfor %}
But as output I get the following
<django.forms.fields.CharField object at 0xb527388c>
<django.forms.fields.IntegerField object at 0xb52738ec>
<django.forms.fields.ChoiceField object at 0xb527394c>
I have read that these are not the same as BoundField object. How to render fields or is there any other better approaches to group fields?
If you do not want use any additional libraries, then the most easy solution is to render them manually, i would say. Otherwise you will just spend alot of time repeating the functionality of the library i copied as comment to your post.
There is always the case that things should be DRY. But we build websites for the users and user cares little about how the form rendering in template is done. For this reason we have often created form templates manually like this:
<div class="something">
{{ form.fieldname.label_tag }}{{ form.fieldname }}
</div>
Easyest way to organise it saving you some time. And in my opinion it is not that bad either, since this is not very common when you need fields organised by fieldsets.
I know this question is rather old, but I am sure there are still people who can benefit from a simple solution:
Say you have a group name and list of members. You can define a self.fieldset in your form's init to be a dictionary of {'group_1': ['member_1', 'member_2', ... ], ... }. Once you attach this to the form, you can pass it to views and from there to the template:
In forms.py:
class MyForm:
def __init__(self, current_user, *args, **kwargs):
super(YourForm, self).__init__(*args, **kwargs)
self.field['group'].queryset = Group.objects.filter(user = current_user)
...
In views.py:
form = self.Form(current_user)
the_fieldsets = form.fieldset
c = {'form': search_form,
'fieldsets': the_fieldsets }
In your template:
{% for field in form %}
<tr>
<td>{{field.label_tag}}</td>
{% if field.name == 'group' %}
<td>
<select id='{{field.id}}' name='{{field.name}}'>
{% for k,v in fieldsets.items %}
<optgroup label = {{k.name}}>
{% for val in v %}
<option name='{{val}} value = {{val.id}}> {{val.name}} </option> # Note that the select needs to return 'id', so value has to be {{val.id}}
{% endfor %}
</optgroup>
{% endfor %}
</select>
</td>
{% else %}
<td>{{field}}</td>
{% endif %}
<td>{{field.help_text}}</td>
<td>{{field.errors}}</td>
</tr>
{% endfor %}