How to loop over multiple fields in Django template? - django

I have models that inherit from an abstract model like this:
class ImprovementAbstraction(models.Model):
needsImprovement = models.BooleanField()
hasFallacies = models.BooleanField()
hasEmotionalDeficiency = models.BooleanField()
isNecessaryToObtain = models.BooleanField()
doesAReallyCauseB = models.BooleanField()
areAllStepsPresent = models.BooleanField()
isCauseSufficient = models.BooleanField()
areAllClausesIdentified = models.BooleanField()
isCausalityCertain = models.BooleanField()
languageIsEnglish = models.BooleanField()
isTautologyPresent = models.BooleanField()
class Meta:
abstract = True
class Assumption(MainAbstractModel, ImprovementAbstraction):
need = models.ForeignKey(Need, on_delete=models.SET_NULL, null=True)
assumption = models.CharField(max_length=500, default="", null=True)
def __str__(self):
return self.assumption
In the template I would like to display all of the "ToImprovementAbstraction" Model fields associated with the Assumption model. Is there a way to loop over all the fields in the template, something like Assumption.ImprovementAbstractionFields.all() (made up code)?

I use the built-in vars() method for that.
For example, you have an Assumption object:
assumptionObject = .models.Assumption.objects.get(pk=1)
If you use vars() method with that query object like this:
vars(assumptionObject)
it will return a dictionary containing all the field names and values as a Python dictionary.
If you only want the field names you can use it like this:
vars(assumptionObject).keys()
EDIT: I should warn you that, if you use vars() on a query object, the returned dictionary will contain a django.db.models.base.ModelState object stored in a key called _state. If you're going to use the values in a for loop or something, you should put an exception for that.

Not exactly sure what your desired outcome is, but this is the basic approach to query data from the database and render the html:
You will first have to query the data from the database like so:
Views.py
def search(request):
queryset = ToImprovementAbstraction.objects.all()
context = {
'queryset': queryset
}
return render(request, 'your_template.html', context)
Then you can use the data to render your template like so:
your_template.html
{% for item in queryset %}
<p>{{ item.needsImprovement }}</p>
[...]
[...]
{% endfor %}
If oyu have multiple models you can make multiple queries to use one/many-to-many fields in your models to link them straight away.

get the assumption object in view and render the ImprovementAbstraction through foreign key. for example:
def get_item():
queryset = Assumption.objects.all()
return render(request, 'template.html', {'queryset': queryset})
Now in your template you can access the data this way
{% for query in queryset %}
{{query.need.needImprovement}}
{{query.need.hasFallacies}}
{{...}}
{% endfor %}
This way you can display everything in one loop. Hope this gets you some idea.

Related

DJANGO Supplement to the data list via an intermediate table

I have an intermediate models connection
Simplified:
class Person(models.Model):
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
etc...
class Company(models.Model):
name = models.CharField(max_length=60)
etc...
class CompanyEnrollment(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
company = models.ForeignKey(Company, on_delete=models.CASCADE)
company_position =
models.ForeignKey(CompanyPosition,on_delete=models.CASCADE)
etc...
class Meta:
unique_together = [['person', 'company']]
class CompanyPosition(models.Model):
name = models.CharField(max_length=60)
I want to create the following array:
datas = Person.objects.All(...{All elements of Person model supplemented with CompanyPosition_name}...)
There is a case where a person does not have a company_name association
Is it possible to solve this with a query?
If you have an explicit through model for your many-to-many relationship, you could use this to only get or exclude based on the entries of this table, using an Exists clause:
enrollments = CompanyEnrollment.objects.filter(person_id=OuterRef('pk'))
enrolled_persons = Person.objects.filter(Exists(enrollments))
unenrolled_persons = Person.objects.filter(~Exists(enrollments))
If you don't have an explicit intermediate table, then it's has been generated by Django directly. You should be able to use it by referring to it with Person.enrollments.through instead of CompanyEnrollment.
Since you did not detailed much the CompanyEnrollment table, I assumed you're in the second case.
This is not the best solution in my opinion, but it works for now, with little data. I think this is a slow solution for a lot of data.
views.py I will compile the two necessary dictionaries
datas = Person.objects.all().order_by('last_name', 'first_name')
companys = CompanyEnrollment.objects.all()
Use Paginator
p = Paginator(Person.objects.all(), 20)
page = request.GET.get('page')
pig = p.get_page(page)
pages = "p" * pig.paginator.num_pages
Render HTML:
context = {
"datas": datas,
"pig": pig,
"pages": pages,
"companys": companys,
}
return render(request, "XY.html", context)
HTML template:
{% for datas in pig %}
{{datas.first_name}} {{datas.last_name}}
{% for company in companys %}
{% if datas == company.person %}
{{company.company.name}} <br>
{% endif %}
{% endfor %}
{% endfor %}
not the most beautiful, but it works ... I would still accept a more elegant solution.

How to render foreignkey relationship in Django

I have a simple ManyToOne relationship where users can post comments to a poller object.
Comments Model
class Comments(models.Model):
poller = models.ForeignKey(Pollers, on_delete=models.CASCADE, related_name='comments')
created_on = models.DateTimeField(auto_now_add=True)
comment = models.CharField(max_length=250)
created_by = models.CharField(max_length=80)
class Meta:
ordering = ['created_on']
def __str__(self):
return 'Comment {} by {}'.format(self.body, self.name)
The View
def single_poller(request, poller_id):
"""retrieves the item clicked by the user from DB and renders
the single_poller template for further user interaction
"""
# Retrieve the item via get
poller = Pollers.objects.get(poller_id=poller_id)
# Increase the view field of the object by
poller.poller_views += 1
# Save the changed instance and overwrite new view integer
poller.save()
# Get the form for comments
form = CommentsForm
context = {
'poller': poller,
'form': form
}
return render(request, 'pollboard/single_poller.html', context)
Now I want to render the comments for each poller into my template like so
<div id="comments-choice-one-wrapper" class="comments-wrapper">
{{ poller.comments.comment }}
</div>
Somehow it doesn't render the comment I created beforehand. I checked in Django admin if the comment is rly related to the poller and this looks just fine.
poller.comments.all is a QuerySet of Comments, so this is a collection, therefore it makes no sense to use .comment since that is an attribute of a Comment object, not an attribute of QuerySet with comments.
You can enumerate over the comments.all, and thus render these comments individually:
<div id="comments-choice-one-wrapper" class="comments-wrapper">
{% for comment in poller.comments.all %}
{{ comment.comment }}
{% endfor %}
</div>
In you Comments model, using self.name or self.body makes not much sense, since that model has no name property or field. You likely should use the __str__ on the Poller:
class Comments(models.Model):
# &vellip;
def __str__(self):
return f'Comment {self.comment} by {self.poller}'
Note: normally a Django model is given a singular name, so Comment instead of Comments.

Can I have data from different fields of a model returned as separate HTML elements? (Django 2.1)

I am compiling a database of articles and have my model set up like this:
class articles(models.Model):
ArticleID = models.IntegerField(primary_key=True)
Title = models.CharField(max_length=500)
Author = models.CharField(max_length=200, null=True)
Journal = models.CharField(max_length=500, null=True)
Date = models.IntegerField(null=True)
Issue = models.IntegerField(null=True)
Link = models.URLField(max_length=800, null=True)
Content = models.TextField()
class Meta:
db_table = 'TEST'
def __str__(self):
return f'{self.Title}, {self.Author}, {self.Journal},{self.Date}, {self.Issue}, {self.Content}'
def get_absolute_url(self):
return reverse('article-detail', args=[str(self.ArticleID)])
The idea is pretty simple. Each meta data type (i.e. title, author) is it's own field, and the actual content of the article is in the field Content.
My view for this model:
def article_detail(request, ArticleID):
ArticleID = get_object_or_404(articles, ArticleID=ArticleID)
context = {'ArticleID': ArticleID}
return render(request, 'article_detail.html', context)
The HTML template for the view:
{% extends 'base.html' %}
{% block content %}
<div class="container">
{{ ArticleID }}
</div>
{% endblock %}
The data displayed in on the HTML page is one big block of text in one single HTML element. How can I make it so that I can use CSS to target each individual field from the model? Must I make separate models for each field (and bound them with foreign keys)?
No of course not. You can access fields with normal dot notation: ArticleID.Title, ArticleID.Author, etc.
(But you shouldn't call your context variable ArticleID; it's the whole article, not the ID. Also, Python style is to use lower_case_with_underscore for variables and attribute names.)
There is already a primary key in for every model which is called id, you don't have to explicitly declare that.
Secondly you are getting an article object with get_object_or_404 so if you use . (dot) notation you will get your desired value in your template.
Something like-
<h2>{{article.Title}}</h2>
<p>{{article.Content}}</p>
though you have to send article names instead of ArticleID in context variable.
In addition to Mr. Daniel Roseman's comment you should use class name Article instead of articles which is not pythonic.

Custom managers in a Many-to-Many relation for usual filters

class Proposal(models.Model):
author = models.ForeignKey(Person, related_name="author")
def get_tags(self):
return Tag.objects.filter(tagged_proposals=self.id)
class Tag(models.Model):
tagged_proposals = models.ManyToManyField(Proposal)
name = models.CharField(primary_key=True, max_length=60)
I need to list the proposal's tags on a certain template so I would write {% for tag in proposal.get_tags %} and it works perfectly.
Now I read about Managers and it seems a good move to convert my get_tags into a Manager. I tried the following but it didn't output a thing. What am I doing wrong? Does it make sense to turn it a Manager in the first place?
class ProposalsTagsManager(models.Manager):
def get_query_set(self):
proposal_id = how-do-i-get-the-proposal-id???
return Tag.objects.filter(tagged_proposals=proposal_id)
usage: {% for tag in p.tags.all %} output: nothing
You don't need a custom function for this.
When a table is being referenced with a ManyToManyField you get a method called MODEL_set to get a queryset of that model.
So in your case you can reference all your tags like this:
proposal = Proposal.objects.get(pk=1)
tags = proposal.tag_set.all() # You can also use filter here

Is it possible for a Django template to test for existence of a row in a table without writing a custom tag/filter?

I have the following models:
class Post(models.Model):
message = models.TextField()
(etc.)
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
(etc.)
class PostFollow(models.Model):
post = models.ForeignKey(Post, related_name='follower_set')
follower = models.ForeignKey(UserProfile, related_name='follower_set')
creation_date = models.DateTimeField(auto_now_add=True)
an_arbitrary_score = models.IntegerField(default=0)
(etc.)
class Meta:
unique_together = ('post', 'follower',)
In my template, I'd like to render a list of posts along with a "follow" or "unfollow" link so that the current user can decide whether to follow a given post. In a world where I could use arguments in Django templating, I'd do something like this:
{% for post in post_set %}
<...stuff...>
{% if post.user_is_following user %}unfollow{% else %}follow{% endif %}
<...more stuff...>
{% endfor %}
However, I can't do that. And I can't make a zero-argument, template-callable method on any of these models, because they all need to know at least one other argument to answer the question whether a given PostFollow row exists in that table.
I'm happy to write a templating extension, but before I bring out the big guns, is this an appropriate case for doing so? Or is there a more Djangoesque solution?
Template filters are not big guns:
# your_app/templatetags/following.py
from django import template
register = template.Library()
#register.filter
def is_followed_by(post, user):
return post.is_followed_by(user)
and then:
{% load following %}
...
{% if post|is_followed_by:user %} ... {% endif %}
You can also put all logic in template filter, remove 'post.is_followed_by' method and use the filter instead of model method just like any other function, #register.filter decorator doesn't harm the decorated function.