I have a model which I want to display as a Detail view, I have created a list view that has a link that leads to its detailed view. I dont get any errors but the template doesn't render any of the models detail
Link to DetailView
<a href="../ancillaries/{{ Ancillary.id }}" > Product </a>
Model
from django.db import models
from django.core.urlresolvers import reverse
class Ancillary(models.Model):
product_code = models.CharField(max_length=60, null=True)
type = models.CharField(max_length=120, null=True)
product = models.CharField(max_length=120, null=True)
standard = models.CharField(max_length=120, null=True)
measurement = models.CharField(max_length=120, null=True)
brand = models.CharField(max_length=120, null=True)
class Meta:
verbose_name_plural = "Ancillaries"
def get_absolute_url(self):
return reverse('ancillaries')
def __unicode__(self):
return u'%s %s %s %s %s %s %s' % (self.id, self.product_code, self.type,
self.product, self.standard,
self.measurement, self.brand)
View
class AncillaryDetail(DetailView):
model = Ancillary
def get_context_data(self, **kwargs):
context = super(AncillaryDetail, self).get_context_data(**kwargs)
context['ancillary_list'] = Ancillary.objects.all()
return context
Urls
url(r'^ancillaries/(?P<pk>\d+)/', AncillaryDetail.as_view(template_name='ancillary-detail.html')),
Template
{% for ancillary_list in object_list %}
{{ Ancillary.product}}
{{ Ancillary.type }}
{{ Ancillary.brand }}
{{ Ancillary.measurement }}
{% endfor %}
It looks as though you've used the documentation but adapted the ListView example incorrectly. If you want to display a single model instance then the DetailView is the correct view.
As #mrkre suggested you should name your URL pattern (although I would use the singular form for the name).
url(r'^ancillaries/(?P<pk>\d+)/', AncillaryDetail.as_view(
template_name='ancillary-detail.html'), name="ancillary_detail")
The view is then simply
class AncillaryDetail(DetailView):
model = Ancillary
In the template ancillary-detail.html you access the model instance using the default name object.
{{ object.product}}
{{ object.type }}
{{ object.brand }}
{{ object.measurement }}
Try:
{% for ancillary in ancillary_list %}
{{ ancillary.product}}
{{ ancillary.type }}
{{ ancillary.brand }}
{{ ancillary.measurement }}
{% endfor %}
I would suggest using names for url:
url(r'^ancillaries/(?P<pk>\d+)/', AncillaryDetail.as_view(), name="ancillary_details")
<a href="{% url 'ancillary_details' pk=ancillary.pk %}">
Place this right after your DetailView
template_name='ancillary-detail.html'
Related
my models:
class Company(models.Model):
name = models.CharField(max_length=250)
def __str__(self):
return str(self.name)
class Products(models.Model):
company = models.ForeignKey(Company, on_delete=models.CASCADE, related_name="display")
engine = models.CharField(max_length=250, blank=True)
cyl = models.CharField(max_length=250, blank=True)
bore = models.CharField(max_length=250, blank=True)
def __str__(self):
return str(self.engine) + " (ref:" + str(self.ref) + ")"
my views.py:
def Companies(request):
context = {
'categories': Company.objects.all()
}
return render(request, 'product_list.html', context)
HTML :
{% for category in categories %}
<h2>{{ category.name }}</h2>
{% for item in category.item_set.all %}
{{ item_engine }}
{% endfor %}
{% endfor %}
how do i display every objects of Products(engine,cyl,bore) following its name
If you want to get related field using ForeignKey try with prefetch_related() method like this
add this in your views.py file
def Companies(request):
context = {
'categories': Products.objects.prefetch_related('company')
}
return render(request, 'product_list.html', context)
this will return object when you try to access your Company object in template like this {{ category.company }} it will give you output like this Company object (1) and you can access all attributes from your Company model.
add this in your template
{% for category in categories %}
<h2>{{ category.company.name }}</h2>
<p>{{ category.engine }}</p>
<p>{{ category.cyl }}</p>
<p>{{ category.bore }}</p>
{% endfor %}
if you delete any Company it will be not displayed on template.
I have two querysets: type and age_group.
type queryset:
<QuerySet [<Type: Cat>, <Type: Dog>, <Type: Other>]>
age_group queryset:
<QuerySet [<AgeGroup: Young>, <AgeGroup: Baby>, <AgeGroup: Adult>, <AgeGroup: Senior>]>
I loop through these from within my template form so that I can grab the pk when one has been selected, but I cannot capture the variable from within the for loop. How do I capture a variable from within a for loop when using Django? I want to capture pk for type and pk for age_group and then use both to filter the model Animal and return a filtered list that matches the user's preferences. A directory search function, essentially.
Template:
{% extends 'base.html' %}
{% block content %}
<h1>Animal Search</h1>
<form class="form-inline" action= '.' method="post">
{% csrf_token %}
<select name= "TypeSearch" class="custom-select my-1 mr-sm-2" id="animal_list_type">
<label class="sr-only type" for="animal_list_type">SEARCH</label>
{% for i in animal_type_list %}
<option value="{{i.pk}}">{{i}}</option> #how to capture the selected pk??
{% endfor %}
</select>
<select name="AgeSearch" class="custom-select my-1 mr-sm-2" id="animal_list_ageGroup">
<label class="sr-only ageLabel" for="animal_list_ageGroup">SEARCH</label>
{% for j in age_group_list %}
<option value="{{j.pk}}">{{j}}</option> #how to capture the selected pk??
{% endfor %}
</select>
<input type="submit" value="SEARCH" onclick="window.location='{% url 'animals:matches_list' pk=4 %}'; return false;">
<input type="submit" onclick="window.location='{% url 'animals:animals' %}'; return false;" value="Cancel">
</form>
{% endblock %}
views.py
class VisitorSearchView(View):
def get(self, request, pk=None):
#first tried ModelForm but couldn't figure out how to capture and iterate through one field of value options at a time
animalList = Animal.type.get_queryset()
animalList2 = Animal.ageGroup.get_queryset()
context = {
"animal_type_list": animalList,
"age_group_list": animalList2
}
return render(request, "animals/landing.html", context)
def post(self, request, pk=None):
theForm1 = AnimalSearchForm(request.POST)
success_url = reverse_lazy('animals:matches_list')
print(pk)
print(theForm1)
filler_for_now = Animals.objects.all()
context = {
'theMatches': filler_for_now
}
return render(request, success_url, context)
model.py
class Animal(models.Model):
name = models.CharField(max_length=500, blank=False, null=False)
type = models.ForeignKey(Type, on_delete=models.SET_NULL, blank=False, null=True)
ageGroup = models.ForeignKey(AgeGroup, max_length=300, on_delete=models.SET_NULL, blank=False, null=True)
age = models.PositiveIntegerField(blank=False, null=False)
sex = models.CharField(max_length=100, choices=SEX, blank=False, null=False, default='NA')
breedGroup = models.ManyToManyField(BreedGroup, blank=False)
breed = models.ManyToManyField(Breed, blank=False)
tagLine = models.CharField(max_length=300, blank=False, null=False)
goodWithCats = models.BooleanField(blank=False, null=False, default='Not Enough Information')
goodWithDogs = models.BooleanField(null=False, blank=False, default='Not Enough Information')
goodWKids = models.BooleanField(null=False, blank=False, default='Not Enough Information')
urls.py
app_name = 'animals'
urlpatterns = [
path('', views.AnimalListView.as_view(), name='animals'),
path('landing/', views.VisitorSearchView.as_view(), name='landing'),
path('matches/<int:pk>', views.VisitorSearchView.as_view(), name='matches_list'),
]
forms.py #(originally tried to use ModelForm but couldn't figure out how to grab the pk for both chooseType and chooseAge fields so chose to try to just use querysets from view)
class AnimalSearchForm(ModelForm):
chooseType = ModelChoiceField(queryset=Animal.objects.values_list('type', flat=True).distinct(),empty_label=None)
chooseAge = ModelChoiceField(queryset=Animal.objects.values_list('ageGroup', flat=True).distinct(), empty_label=None)
class Meta:
model = Animal
exclude = '__all__'
Outside of Django, this would be a simple problem to solve. How do I capture a variable from within a for loop when using Django? I have tried to instantiate a variable outside the for-loop and then update that based off selection from within, but it seems that this cannot be done via the template...?
Well the real issue here is that you really should be using FormView to display a form together with DetailView to display model data, in this particular case you should do something like this:
views.py
from django.views.generic import FormView, DetailView
class VisitorSearchView(FormView, DetailView):
model = Animal
template_name = 'animals/landing.html'
form_class = AnimalSearchForm
def form_valid(self, form):
data = form.cleaned_data # Dict of submitted data
# handle form validation and redirect
def get_context_data(self, request):
context = super(VisitorSearchView, self).get_context_data(**kwargs)
animals = Animal.objects.all() # or use a custom filter
context['animals'] = animals
return context
Then in your landing.html
where you want a list of animal types:
{% for animal in animals %}
{{ animal.type }}
{% endfor %}
and where you want a list of animal ages:
{% for animal in animals %}
{{ animal.age }}
{% endfor %}
declare your form normally as you would.
I think you need to remove the dot from the action attribute. Empty string in action use the current URL for form submission. Form opening line will be like
<form class="form-inline" action= '' method="post">
I am struggling with Django forms.
I have the following model.py:
class Property(models.Model):
portfolio = models.ForeignKey("portfolios.Portfolio", on_delete=models.CASCADE)
class PropertyImage(models.Model):
property = models.ForeignKey("Property", on_delete=models.CASCADE)
image = models.ImageField(upload_to = property_image_upload_to)
def __str__(self):
return self.image.url
class PropertyDocument(models.Model):
property = models.ForeignKey("Property", on_delete=models.CASCADE)
document = models.FileField()
class Address(models.Model):
property = models.OneToOneField("Property", on_delete=models.CASCADE)
line1 = models.CharField(max_length=100)
line2 = models.CharField(max_length=100, null=True, blank=True)
line3 = models.CharField(max_length=100, null=True, blank=True)
post_code = models.CharField(max_length=7)
town = models.CharField(max_length=100, null=True, blank=True)
city = models.CharField(max_length=100)
When adding/updating a property, I want the form to show the form for related objects like the address, documents/images instead of the select list's that appear in forms - I want to be able to add/edit the related data.
My view.py file
class PropertyCreate(CreateView):
model = Property
form_class=PropertyAddressFormSet
success_url = reverse_lazy('Property_list')
def get_context_data(self, **kwargs):
data = super(PropertyCreate, self).get_context_data(**kwargs)
return data
Property_form.html
{% extends 'base/base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<form method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" class="btn btn-primary" />
<button class="btn btn-link" onclick="javascript:history.back();">Cancel</button>
</form>
{% endblock %}
urls.py
from . import views
app_name = 'properties'
urlpatterns = [
path('<int:portfolio_id>/<int:pk>/edit', views.PropertyUpdate.as_view(), name='property_edit'),
path('<int:portfolio_id>/create', views.PropertyCreate.as_view(), name='property_new'),
]
I've read about inlineformset_factories and inlineformset's etc, but is this the best choice for my scenario? If so, I can't figure out how to show the portfolio, address form
I;m currently using a inlineformset like so, which creates the Address form on the PropertyCreate view, but I want to also add in the PropertyImages and PropertyDocs to the ProertyCreate view.:
PropertyAddressFormSet = inlineformset_factory(
parent_model=Property,
model=Address,
form=AddressForm,
extra=0,
min_num=1
)
For anyone in the same boat as me, I managed to get this working with the following code:
Forms.py:
class PropertyForm(ModelForm):
""" Edit a property """
class Meta:
model = Property
exclude = ()
PropertyAddressFormSet = inlineformset_factory(
parent_model=Property,
model=Address,
form=AddressForm,
extra=0,
min_num=1
)
Views.py
class PropertyCreate(CreateView):
model = Property
form_class=PropertyForm
success_url = reverse_lazy('Property_list')
def get_context_data(self, **kwargs):
data = super(PropertyCreate, self).get_context_data(**kwargs)
if self.request.POST:
data['address'] = PropertyAddressFormSet (self.request.POST, instance=self.object)
else:
data['address'] = PropertyAddressFormSet ()
return data
template:
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form |crispy }}
<fieldset class="border p-2">
<legend class="w-auto">Address</legend>
{{ address.management_form }}
{% for form in address.forms %}
<div >
{{ form.as_p }}
</div>
{% endfor %}
</fieldset>
</form>
Hope this helps someone.
I'm very new to Django and have the a model with the ManyToMany field. I'm trying to surface the tag names in my html. If I use {{ listing.tag }} in my template I get something like <django.db.models.fields.related.ManyRelatedManager object at 0x10916f410> and {{ listing.tag.name }} doesn't show anything.
Here is my model:
from django.db import models
from django_extensions.db.fields import AutoSlugField
class Tag(models.Model):
name = models.CharField(max_length=100)
slug = AutoSlugField(populate_from='name', unique=True)
def __unicode__(self):
return self.name
class Listings(models.Model):
listing = models.CharField(max_length=50)
description = models.CharField(max_length=500)
email = models.EmailField(max_length=75)
tag = models.ManyToManyField(Tag)
pub_date = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.listing
How would I show the name of the tag? Thanks in advance.
Since ManyToMany returns a queryset, you need to loop through the queryset.
You can access the queryset this way: {{ listing.tag.all }}
and you can access it this way
{% for tag in listing.tag.all %}
{{tag.name}}
{% endfor %}
You should loop through your set of tags:
{% for tag in listing.tag.all %}
{{ tag.name }}
{% endfor %}
If you just need __str__ (or equivalent) and a simple join, this will work:
{{ listing.tag.all|join: ", "}}
Reference: https://docs.djangoproject.com/en/1.11/ref/templates/builtins/#join
Here are my two models
class Category(models.Model):
name = models.CharField(max_length = 50)
description = models.CharField(max_length = 1000)
created = models.DateTimeField(auto_now_add=True)
def __unicode__(self, ):
return self.name
class Post(models.Model):
subject = models.CharField(max_length=50, blank=True)
description = models.CharField(max_length=1000)
created = models.DateTimeField(auto_now_add=True)
category = models.ManyToManyField(Category)
def __unicode__(self, ):
return self.subject
I'm displaying the subject, description, and date of each post in a template. But I also want to display the respective category for each post as well.
Here's the part of my view
def index(request):
posts = Post.objects.order_by("-created")
return render(request,'posts/index.html', {'posts':posts})
and then how I'm trying to display it in a template:
{% for post in posts %}
<div>
{{ post.subject }}<br />
{{ post.description }}<br />
{{ post.created }} | of {{ post.category }}
</div>
{% endfor %}
But the category will not show up, all I get is
<django.db.models.fields.related.ManyRelatedManager object at 0x7ff7e40a0c90>
I've tried doing post.category.name and other random combinations but it either gives nothing or a parsing error. I have no idea how to get the category displayed.
That's a Manager. Use it as you would any other Manager (e.g. Post.objects).
{% for category in post.category.all %}