I'm trying to get annotations showing in my templates. I have two models (model1 and model2) and I want to show the number of model2's related to model1.
Here is my views.py:
def model2_count(request, pk):
model2count = models.Model1.objects.filter(pk=model1.pk).annotate(title_count=Count(‘model2__title'))
return render(request, 'model1/_model1.html', {‘m2c’: model2count})
Here is the template (model1/_model1.html):
I tried this:
{% for object in m2c %}</h3>
{{ object.title }}
{{ object.title_count }}
{% endfor %}
And tried this:
{% if m2c.title_count %}
{{ m2c.title_count }}
{% endif %}
I've been pulling my hair out over this for a couple days and can't figure it out. The following has been largely unhelpful:
Django - Annotating Weighted AVG by Group
Django: Annotation not working?
Django templates are not showing values of annotations
Django annotated value in template
What's frustrating is that I can't even say why applying these solutions hasn't worked.
Any input is appreciated.
Also, here are my models with all the BS taken out.
class Publication(models.Model):
title = models.CharField(max_length=150, unique=False, blank=False)
contributors_note = models.TextField(max_length=300, blank=False)
website = models.URLField()
publisher = models.CharField(max_length=250, unique=False)
publication_date = models.DateField(default=datetime.date.today)
slug = models.SlugField(allow_unicode=True, unique=False)
content_type = models.CharField(max_length=100, unique=False)# In this field user's define the type of content (blog, newspaper article, publication etc)
research_type = models.CharField(max_length=100, unique=False)# In this field user's define whether the research is based on primary or secondary research
user = models.ForeignKey(Current_user, related_name="publication")
created_at = models.DateTimeField(auto_now_add=True)
last_updated = models.DateTimeField(auto_now=True)
category = models.ForeignKey(Category, related_name="publication",null=True, blank=False)
comment = models.TextField()
def __str__(self):
return self.title
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse(
"publication:single",
kwargs={
"username": self.user.username,
"pk": self.pk
}
)
class Meta:
ordering = ["-created_at"]
class Assessment(models.Model):
title = models.CharField(max_length=150, unique=False, blank=False)
publication = models.ForeignKey('publication.Publication', on_delete=models.CASCADE, related_name='assessment')
analyst = models.ForeignKey(Current_user, null=True, blank=True, related_name="assessment")
created_at = models.DateTimeField(auto_now_add=True)
approved_comment = models.BooleanField(default=False)
key_finding1 = models.TextField(max_length=300)
key_finding2 = models.TextField(max_length=300)
key_finding3 = models.TextField(max_length=300)
ratings_range = (
('1', 'Very Weak'),
('2', 'Weak'),
('3', 'Moderate'),
('4', 'Strong'),
('5', 'Very Strong'),
)
content_rating_1 = models.CharField(max_length=1, choices=ratings_range)
content_rating_1_comment = models.TextField(max_length=300)
content_rating_2 = models.CharField(max_length=1, choices=ratings_range)
content_rating_2_comment = models.TextField(max_length=300)
content_rating_3 = models.CharField(max_length=1, choices=ratings_range)
content_rating_3_comment = models.TextField(max_length=300)
content_rating_4 = models.CharField(max_length=1, choices=ratings_range)
content_rating_4_comment = models.TextField(max_length=300)
content_rating_5 = models.CharField(max_length=1, choices=ratings_range)
content_rating_5_comment = models.TextField(max_length=300)
source_rating_1 = models.CharField(max_length=1, choices=ratings_range)
source_rating_1_comment = models.TextField(max_length=300)
source_rating_2 = models.CharField(max_length=1, choices=ratings_range)
source_rating_2_comment = models.TextField(max_length=300)
source_rating_3 = models.CharField(max_length=1, choices=ratings_range)
source_rating_3_comment = models.TextField(max_length=300)
source_rating_4 = models.CharField(max_length=1, choices=ratings_range)
source_rating_4_comment = models.TextField(max_length=300)
source_rating_5 = models.CharField(max_length=1, choices=ratings_range)
source_rating_5_comment = models.TextField(max_length=300)
def approve(self):
self.approved_comment = True
self.save()
def __str__(self):
return self.title
class Meta:
ordering = ["-created_at"]
Bad mistake on my part. The solution's given above worked. Here is my final code:
views.py
class PublicationDetail(SelectRelatedMixin, generic.DetailView):
model = models.Publication
select_related = ("category", "user")
def get_queryset(self):
queryset = super().get_queryset()
return queryset.filter(user__username__iexact=self.kwargs.get("username")).annotate(assessment_count=Count('assessment'))
Fellow noobs that follow:
- It's easier for the people that want to help you (and faster for you) if you just post your original code instead of trying to get smart. Don't be embarrassed. I would've saved us all time if I had just done that.
First aggregations are done only using the field name i.e model2 not model2__title
Next getting counts of annotated columns recommended to use .values or values_list but not required.
https://docs.djangoproject.com/es/2.1/topics/db/aggregation/#cheat-sheet
model1 = Model1.objects.get(pk=model1.pk)
model2count = (
Model1.objects.annotate(count=Count('model2'))
.filter(pk=model1.pk)
.values_list('title', 'count', named=True)
)
template.html
{% for object in model2count %}
{{ object.title }}
{{ object.count }}
{% endfor %}
Related
Views.py
def PostView(request,slug):
Postdata = Post.objects.get(slug=slug)
side_data = Post.objects.all()
category_posts = Post.objects.filter(category__cat_slug=slug)
return render(request,'post-detail.html',{'Postdata':Postdata,'side_data':side_data,'category_posts':category_posts})
Models.py
class Category(models.Model):
name = models.CharField(max_length=100)
category_description = FroalaField()
cat_slug = models.SlugField(max_length=200, null=False)
def __str__(self):
return self.name
options = (
('draft', 'Draft'),
('published', 'Published'),
)
class Post(models.Model):
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200, unique=True)
category = models.ForeignKey(
Category, on_delete=models.CASCADE,null=True,)
author = models.ForeignKey(User, on_delete= models.CASCADE,related_name='myapp_post')
updated_on = models.DateTimeField(auto_now= True)
content = FroalaField()
feature_img = models.ImageField(upload_to = 'images/', null=False)
status = models.CharField(max_length=10, choices=options, default='draft')
created_on = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-created_on']
def __str__(self):
return self.title
Post-detail.html
<h4>Related Post</h4>
<br>
{% for data in category_posts %}
<h4>{{data.title}}</h4>
{% endfor %}
I'm trying to Add Category Related latest Posts in the Article.
For Example
If an article in which category name is Django Tutorial. In the Article Detail, I want to add the Related latest post of this category.
you can try this :
Post.objects.filter(slug=slug).order_by('-id')[0]
order by id will give you the last one added
or you can use directly :
Post.objects.filter(slug=slug).last()
I have got 2 models. Asset and Asset_Type. In my asset_type detail view i would like to list all assets of that asset type. I think I have to use models.Asset.queryset().filter() but i can't get it to work.
On my template I would like to loop though the list with a 'for' (example: object in list) and print the values like this {{ object.name }}
models.py
class Asset(models.Model):
# Relationships
room = models.ForeignKey("asset_app.Room", on_delete=models.SET_NULL, blank=True, null=True)
model_hardware = models.ForeignKey("asset_app.Model_hardware", on_delete=models.SET_NULL, blank=True, null=True)
# Fields
name = models.CharField(max_length=30)
serial = models.CharField(max_length=30, unique=True, blank=True, null=True, default=None)
mac_address = models.CharField(max_length=30, null=True, blank=True)
purchased_date = models.DateField(null=True, blank=True)
may_be_loaned = models.BooleanField(default=False, blank=True, null=True)
notes = models.TextField(max_length=448, null=True, blank=True)
ip = models.CharField(max_length=90, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True, editable=False)
last_updated = models.DateTimeField(auto_now=True, editable=False)
class Meta:
ordering = ["name"]
def __str__(self):
return str(self.name)
def get_absolute_url(self):
return reverse("asset_app_asset_detail", args=(self.pk,))
def get_update_url(self):
return reverse("asset_app_asset_update", args=(self.pk,))
class Asset_type(models.Model):
# Fields
name = models.CharField(max_length=30)
last_updated = models.DateTimeField(auto_now=True, editable=False)
created = models.DateTimeField(auto_now_add=True, editable=False)
notes = models.TextField(max_length=448, null=True, blank=True)
class Meta:
ordering = ["name"]
def __str__(self):
return str(self.name)
def get_absolute_url(self):
return reverse("asset_app_asset_type_detail", args=(self.pk,))
def get_update_url(self):
return reverse("asset_app_asset_type_update", args=(self.pk,))
class Model_hardware(models.Model):
# Relationships
asset_type = models.ForeignKey("asset_app.Asset_type", on_delete=models.SET_NULL, blank=True, null=True)
brand = models.ForeignKey("asset_app.Brand", on_delete=models.SET_NULL, blank=True, null=True)
# Fields
name = models.CharField(max_length=30)
notes = models.TextField(max_length=448, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True, editable=False)
last_updated = models.DateTimeField(auto_now=True, editable=False)
class Meta:
ordering = ["name"]
def __str__(self):
return str(self.name) + " :: " + str(self.brand.name) + " :: " + self.asset_type.name
def get_absolute_url(self):
return reverse("asset_app_model_hardware_detail", args=(self.pk,))
def get_update_url(self):
return reverse("asset_app_model_hardware_update", args=(self.pk,))
views.py
class Asset_typeDetailView(generic.DetailView):
model = models.Asset_type
form_class = forms.Asset_typeForm
You can simply iterate over the related objects in the template by using the default related name which is the model name in lowercase with _set appended. So asset_type.model_hardware_set.all() will give you all Model_hardware instances related to Asset_type and similarly for model_hardware.asset_set.all():
{% for model_hardware object.model_hardware_set.all %}
{% for asset in model_hardware.asset_set.all %}
{{ asset.name }}
{% endfor %}
{% endfor %}
But this can become slow, since we run into the N + 1 problem that is for each model hardware we will be making queries to get it's assets. We can use prefetch_related_objects on your model instance to prefetch all the related objects (in fewer queries) this and make it faster:
from django.db.models import prefetch_related_objects
from django.views.generic import DetailView
class YourDetailView(DetailView):
model = Asset_type
template_name = '<your_template_name>.html'
def get_object(self, queryset=None):
obj = super().get_object(queryset=queryset)
prefetch_related_objects([obj], 'model_hardware__asset')
return obj
Note: Class names in python should ideally be in PascalCase not Some_case (Don't think there is any such convention as you make
here), hence ModelHardware instead of Model_hardware and
AssetType instead of Asset_type would be better names.
I have the view which displays all transactions. I have a table with contractors and I want to display all rows from this table in the options to <select>. How can i do this?
My view:
class TransactionView(CustomPermissionRequired, ListView):
# Переопределение из MultipleObjectMixin
model = Transaction
context_object_name = 'transactions'
paginate_by = 20
login_url = '/'
permission_required = (
'registration2.can_see_payments',
)
# Переопределение из TemplateResponseMixin
template_name = 'payments.html'
search_fields = [
('contractor_name', 'deal__service__contractor__name__icontains'),
('from_pay_date', 'payment_date__gte'),
('to_pay_date', 'payment_date__lte'),
('tr_id', 'id__icontains')
]
# Переопределение из MultipleObjectMixin
def get_queryset(self):
print('get_def')
filter_args = []
filter_kwargs = {}
for sf in self.search_fields:
if sf[0] is not None:
sf_value = self.request.GET.get(sf[0])
if sf_value:
filter_kwargs[sf[1]] = sf_value
return Transaction.objects.all().select_related('currency',
'payment_source__payment_type',
'deal__service__contractor'
).filter(*filter_args, **filter_kwargs).order_by('-id')
def get_context_data(self, **kwargs):
context = super(TransactionView, self).get_context_data(**kwargs)
for sf in self.search_fields:
if sf[0] is not None:
context[sf[0]] = self.request.GET.get(sf[0])
return context
My models Transaction and Contractors:
class Transaction(models.Model):
id = models.BigIntegerField(blank=True, null=False, primary_key=True)
currency = models.ForeignKey(Currency, null=True, on_delete=models.CASCADE)
deal = models.ForeignKey(Deal, null=True, on_delete=models.CASCADE)
# service_instance = models.ForeignKey(ServiceInstance, null=True, on_delete=models.CASCADE)
payment_source = models.ForeignKey(PayerPaymentSource, null=True, on_delete=models.CASCADE)
payment_date = models.DateTimeField(blank=True, null=True)
amount = models.IntegerField(blank=True, null=True)
status = models.CharField(max_length=255, blank=True, null=True)
context = models.TextField(blank=True, null=True)
class Contractors(models.Model):
id = models.IntegerField(blank=True, null=False, primary_key=True)
name = models.CharField(max_length=255, blank=True, null=True)
You don't show your HTML, but you start from a queryset to get the contractor names and ids.
contractors = Contractors.objects.all().order_by('name').values_list('id, 'name')
If you look at list(contractors) you will see it is a list of 2-tuples as required for choices.
You can use it as such if you dynamically build a form, or you can pass it to your template and iterate through it there to build an options list
{% for c in contractors %} <option ... {{c.0}} ... {{c.1}} ... {% endfor %}
There's also forms.ModelChoiceField which IIRC accepts a queryset (without values_list()) as an argument, and returns the selected [Contractor] instance as its entry in form.cleaned_data.
I'm trying to add extra content to Djangos Class-based view to the template
I have some models like this
class District(models.Model):
district = models.CharField(max_length=255, null=False, unique=False, blank=True)
def __str__(self):
return self.district
class Street(models.Model):
street_name = models.CharField(max_length=255, null=False, unique=False, blank=True)
district = models.ForeignKey(District, verbose_name=_('district'), on_delete=models.CASCADE, null=True, blank=True)
zone = models.IntegerField(blank=True, null=True)
def __str__(self):
return self.street_name
class Article(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, related_name="author", on_delete=models.SET_NULL)
timestamp = models.DateTimeField(auto_now_add=True)
status = models.CharField(max_length=1, choices=STATUS, default=CREATED)
comment = models.CharField(max_length=255, null=True, unique=False, blank=True)
name = models.CharField(max_length=255, null=True, unique=False)
street = models.ForeignKey(Street, verbose_name=_('street'), on_delete=models.CASCADE, null=True, blank=True)
class ArticlesListView(LoginRequiredMixin, PermissionRequiredMixin,ListView):
model = Article
paginate_by = 50
context_object_name = "articles"
permission_required = 'is_staff'
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context['Filter_name'] = Article.objects.order_by().values('name').distinct()
context['Filter_user'] = Article.objects.order_by().values('user').distinct()
return context
def get_queryset(self, **kwargs):
return Article.objects.all()
And late in the template
{% for f in Filter_name %}
<ul>
<li>{{f.name}}</li>
</ul>
{% endfor %}
How can I display a list of the district names and a list of the author names in the template with ForeignKey?
U can try something like that
{% for item in model_1.foreign_model_set.all %}
<h1>{{ item }}</h1>
{% endfor %}
I plan to get rid of the related name the next time I rebuild the database...the models I am using are more of test-models. So, with Class Creator and the writer, cover_artist, etc., how would I go about displaying the issues that Creator has created (once I get rid of the related name, unless there's a way to go around it)?
class Creator(models.Model):
name = models.CharField(max_length=256)
desc = models.TextField("description", blank=True, null=True)
#type = writer, artist, editor, letterer
slug = models.SlugField(blank=True, null=True)
def __unicode__(self):
return self.name
class Meta:
ordering = ['name']
def get_absolute_url(self):
return "/comics2/creators/%s" % self.slug
class Issue(models.Model):
....
writer = models.ManyToManyField(Creator, related_name="written by", help_text="Use cmd/ctrl + click to select multiple names. The same applies to the rest of the creators below.", blank=True, null=True)
artist = models.ManyToManyField(Creator, related_name="drawn by", blank=True, null=True)
cover_artist = models.ManyToManyField(Creator, related_name="cover drawn by", blank=True, null=True)
colorist = models.ManyToManyField(Creator, related_name="colored by", blank=True, null=True)
inker = models.ManyToManyField(Creator, related_name="inked by", blank=True, null=True)
penciller = models.ManyToManyField(Creator, related_name="pencilled by", blank=True, null=True)
letterer = models.ManyToManyField(Creator, related_name="lettered by", blank=True, null=True)
editor = models.ManyToManyField(Creator, related_name="edited by", blank=True, null=True)
arc = models.ManyToManyField(Arc, related_name="related story arc", blank=True, null=True)
...
def __unicode__(self):
return u'%s %s' % (self.title, self.number)
def get_absolute_url(self):
return "/comics2/issues/%s" % self.slug
class Meta:
ordering = ['title', 'number']
def get_stars(self):
star_rating = self.rating * 16
return star_rating
....
{% for issue in creator.____?__.all %}
<ul>
<li>{{ issue }}</li>
</ul>
{% endfor %}
Is not going to work.
Thanks.
I would suggest changing your models.py to have Issue have a Many to Many relationship to Creator through another table, e.g. Role. See docs here.
class Creator(models.Model):
name = models.CharField(max_length=256)
desc = models.TextField("description", blank=True, null=True)
slug = models.SlugField(blank=True, null=True)
def __unicode__(self):
return self.name
class Meta:
ordering = ['name']
def get_absolute_url(self):
return "/comics2/creators/%s" % self.slug
class Issue(models.Model):
creators = models.ManyToManyField(Creator, through='Role')
arc = models.ManyToManyField(Arc, related_name="related story arc", blank=True, null=True)
...
def __unicode__(self):
return u'%s %s' % (self.title, self.number)
def get_absolute_url(self):
return "/comics2/issues/%s" % self.slug
class Meta:
ordering = ['title', 'number']
def get_stars(self):
star_rating = self.rating * 16
return star_rating
class Role(models.Model):
issue = models.ForeignKey(Issue)
creator = models.ForeignKey(Creator)
role = models.CharField()
...
edit:
in your issues view, you would get the different roles and pass it to your template (for example):
def issue_detail(request, issue_slug=None):
issue = get_object_or_404(Issue, slug=creator_slug)
writers = issue.creators.filter(role__role='writer')
cover_artists = issue.creators.filter(role__role='cover artist')
...
context = { 'issue': issue,
'writers': writers,
'cover_artists': cover_artists,
...
}
return render_to_response('issue_detail.html', context,
context_instance=RequestContext(request))
template:
<label>Writers</label>
{% for writer in writers %}
{{ writer }}
{% endfor %}
<label>Cover Artists</label>
{% for cover_artist in cover_artists %}
{{ cover_artist }}
{% endfor %}
creator view:
def creator_detail(request, issue_slug=None):
creator = get_object_or_404(Creator, slug=issue_slug)
issues_as_writer = creator.issue_set.filter(role__role='writer')
issues_as_cover_artists = creator.issue_set.filter(role__role='cover artist')
#all issues related to this creator
all_issues = creator.issue_set.all()
...
context = { 'creator': creator,
'issues_as_writer': issues_as_writer,
'issues_as_cover_artist': issues_as_cover_artist,
...
'all_issues': all_issues,
}
return render_to_response('creator_detail.html', context,
context_instance=RequestContext(request))