I have following model created in Django:
class Content(models.Model):
publish_date = models.DateTimeField(auto_now_add=True)
name = models.CharField(max_length = 100, blank = False, default='name')
summary = models.CharField(max_length=400, blank=True, default='summary')
description = models.TextField(blank = True, max_length=5000, default = LOREM_IPSUM)
author = models.ForeignKey(User, default=None, on_delete=models.CASCADE)
rules = models.TextField(blank = True, default='rule set')
parent = models.ManyToManyField(to = 'self', related_name="child", symmetrical = False, blank=True)
I added four Content objects through Django admin:
Project1
Task1
Task2
Task3
And set parent to Project1 for all TaskX. When I want to display all the content with detailed parent atrribute it turns out to be None.
views.py
def display_ideas(request):
ideas = Content.objects.filter(name="Task3")
return render(request, 'display_ideas.html', context = { 'ideas' : ideas })
** display_ideas.html **
<div class="container bg-success">
{% for idea in ideas %}
<div class="container bg-danger">
<h2>Name:</h2>
{{ idea.name }} has parent: {{ idea.parent.name }}
</div>
{% endfor %}
</div>
The output is:
Name:
Task3 has parent: None
What am I doing wrong? All migrations are done and the site is up and running.
Since its a ManyToMany field content object may have more than 1 parent, thats why {{ idea.parent.name }} Does not work. You would have to iterate through each parent as you have done here for ideas {% for idea in ideas %}, to show the parent attributes.
Currently, the parent is a ManyToManyField and you can't access it directly so try to use nested loop so:
<div class="container bg-success">
{% for idea in ideas %}
<div class="container bg-danger">
<h2>Name:</h2>
{{ idea.name }} has parent(s):
{% for parent in idea.parent.all %}
{{ parent.name }},
{% endfor %}
</div>
{% endfor %}
</div>
Related
I want to check if the logged in user is the author of a post in my Forum. I have written some code to figure that out:
<div class="right-section-posts">
user: {{ user }} <!--Output: Admin-->
author: {{ post.author }} <!--Output: Admin-->
{% if user == post.author %}
<form action="DELETE">
{% csrf_token %}
<button type="submit" class="delete-btn" name="post-id" value="{{ post.id }}">Delete</button>
</form>
<button class="edit-btn">Edit</button>
{% endif %}
</div>
They both output the same but the statement returns false! Why?
Models.py
class Post(models.Model):
vote_count = models.IntegerField(default=0)
id = models.BigAutoField(primary_key=True)
created_at = models.DateField(default=date.today)
title = models.CharField(max_length=100)
description = models.CharField(max_length=1000)
tags = models.CharField(max_length=200)
author = models.CharField(max_length=100, default="none")
def __str__(self):
return str(self.id) + ' ' + self.title
I tried different ways to get the Current user and the author. Doesn't work to.
(I think you might say that I should use ForeignKey instead of ´CharField´, when using that I get this Error:
ERROR: Column forum_app_post.author_id does not exist.
LINE 1: ...app_post". "description", "forum_app_post". "tags", "forum_app...
^
HINT: Perhaps the intention was to refer to the "forum_app_post.author" column.
)
The author field cannot be a CharField because it represents the user. You need to set author field as foreignkey.
You need to update your model like this:
from django.contrib.auth.models import User
class Post(models.Model):
vote_count = models.IntegerField(default=0)
id = models.BigAutoField(primary_key=True)
created_at = models.DateField(default=date.today)
title = models.CharField(max_length=100)
description = models.CharField(max_length=1000)
tags = models.CharField(max_length=200)
author = models.ForeignKey(User,on_delete= models.CASCADE, verbose_name='Post Author')
def __str__(self):
return str(self.id) + ' ' + self.title
If you want to check the logged in user from all the registered posts, you should get all the posts first.
def get_all_posts(request):
posts = Post.objects.filter.all()
context = {
"posts" : posts,
}
return render(request,"my_page.html",context)
Then in the html page :
<div class="right-section-posts">
{% if posts %}
{% for post in posts %}
{% if request.user == post.author %}
<!--do what you want here-->
{% else %}
{% endif %}
{% endfor %}
{% else %}
<div class="alert alert-info">You have no registered post yet!</div>
<!-- /.container-fluid -->
</div>
{% endif %}
</div>
I also recommend using django-taggit for tags.
My goal is to list the tag_titles for each note created.
I am having issues because the tag_title and note are linked through a Many to Many relationship.
How I would normally do this is:
{% for note_tag in note_tags %}
{% if note_tag.note == note %}
{{note_tag.tag_title}}
{% endif %}
{% endfor %}
However, because tag_title has a many to many relationship with NoteModel, note_tag.note gives out notes.NoteModel.None
My models.py are as follows:
class NoteModel(models.Model):
note = models.CharField(
max_length = 5000,
)
note_title = models.CharField(
max_length = 500,
blank = False,
null = True,
)
project = models.ForeignKey(
IndividualProject,
on_delete=models.CASCADE,
related_name = "note_projects",
blank = False,
null = True,
)
tag = models.ManyToManyField(
'NoteTagModel',
related_name="tags",
blank= False,
through = "TaggedModel"
)
def __str__(self):
return f"{self.note_title}"
class NoteTagModel(models.Model):
note = models.ManyToManyField(
'NoteModel',
related_name="tag_notes",
blank= False,
through = "TaggedModel"
)
tag_title = models.CharField(
max_length = 200,
default = "General",
)
def __str__(self):
return f"{self.tag_title}"
class TaggedModel(models.Model):
note = models.ForeignKey(NoteModel, on_delete = models.CASCADE)
tag = models.ForeignKey(NoteTagModel, on_delete = models.CASCADE)
def __str__(self):
return f"{self.note} | {self.tag}"
class TagCommentaryModel(models.Model):
tag_title = models.ForeignKey(
NoteTagModel,
on_delete=models.CASCADE,
related_name="tag",
blank = False,
null = True,
)
tag_commentary = models.CharField(
max_length = 5000
)
def __str__(self):
return f"Tag: {self.tag_title} | Tag Commentary: {self.tag_commentary}"
The context in my views.py is as follows:
context = {
'note_form' : note_form,
'notes' : NoteModel.objects.filter(project = obj),
'notes_tag' : NoteTagModel.objects.all(),
'commentary' : TagCommentaryModel.objects.all(),
'projects' : IndividualProject.objects.all(),
'specific_project' : IndividualProject.objects.get(id=id),
'obj' : IndividualProject.objects.get(id=id),
'tagged' : TaggedModel.objects.all(),
}
return render(request, "notes/specific-note.html", context)
My django template is as follows:
<div class = note_overview_container>
{% for note in notes %}
<div class = individual_note_container>
<div class = note_title>
{{ note.note_title }}
</div>
{% for note_tag in notes_tag %}
<div class = tag_title>
{{ note_tag.tag_title }}
</div>
<ul class = tag_commentary>
{% for commentary in commentary %}
{% if note_tag == commentary.tag_title %}
{% if note == commentary.note %}
<li>{{ commentary.tag_commentary }}</li>
{% endif %}
{% endif %}
{% endfor %}
</ul>
{% endfor %}
</div>
{% endfor %}
</div>
You can simplify your models a lot in my opinion. You point from tag in NoteModel to NoteTagModel and vice versa & I don’t think it is needed.
Also TaggedModel seems superfluous. At least if there isn't a specific reason to link it like you did.
class NoteModel(models.Model):
note = models.CharField(max_length = 5000)
note_title = models.CharField(max_length=500, blank=False, null=True)
project = models.ForeignKey(IndividualProject, on_delete=models.CASCADE, related_name="note_projects", blank=False, null=True)
# plural
tags = models.ManyToManyField(NoteTagModel, related_name="tags", blank=False)
def __str__(self):
return self.note_title
class NoteTagModel(models.Model):
# usually there is no need to point here again to the same model thats already pointing to this one
tag_title = models.CharField(max_length=200, default="General")
def __str__(self):
return self.tag_title
If you want to access reverse from NoteTagModel to NoteModel, you can do the following eg:
for tag in NoteTagModel.objects.all():
for note in tag.nodemodel_set.all():
print(note.note_title)
…
(I put the html classes in double quotes)
<div class="note_overview_container">
{% for note in notes %}
<div class="individual_note_container">
<div class="note_title">
{{ note.note_title }}
</div>
<!-- loop over all the tags related to the note -->
{% for tag in note.tags.all %}
<div class=”tag_title”>
{{ tag.tag_title }}
</div>
<ul class="tag_commentary">
<!-- commentary in commentary shouldnt be named the same -->
{% for comment in commentary %}
{% if note_tag == comment.tag_title %}
{% if note == comment.note %}
<li>{{ comment.tag_commentary }}</li>
{% endif %}
{% endif %}
{% endfor %}
</ul>
{% endfor %}
</div>
{% endfor %}
</div>
I want to count how many jobs are open vs closed. I don't understand why this isn't working, I have added {{ap.id}} and {{open.line_num_id }} after the forloop just to see what was rendered. I would think that if they match, then it's added to the count. This is not the case, all jobs are counted regardless of the "if" statement. Totally lost as to what is happening and why. Any help would be very appreciated .
I have two models:
class Airplane(models.Model):
line_num = models.CharField(max_length=10, unique=True)
vh_num = models.CharField(max_length=4, unique=True)
vz_num = models.CharField(max_length=4, unique=True)
stall = models.CharField(max_length=30, choices=stall_picker)
status = models.CharField(max_length=30, choices=status_picker)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
is_completed = models.BooleanField(default=False)
pm = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.line_num
class Job(models.Model):
line_num = models.ForeignKey(
Airplane, on_delete=models.CASCADE, related_name="ap_jobs")
job_num = models.CharField(max_length=10, unique=True)
description = models.CharField(max_length=200)
status = models.CharField(max_length=30, choices=status_picker)
category = models.CharField(max_length=30, choices=categories_picker)
is_completed = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class meta:
ordering = ["category", "status"]
def __str__(self):
return (f"{self.job_num}: {self.description} : {self.is_completed}")
My View:
def Ap_linup(request):
context = {
'ap_list': Airplane.objects.all().filter(is_completed=False),
'open_jobs': Job.objects.all().filter(is_completed=False),
'closed_jobs': Job.objects.all().filter(is_completed=True)
}
return render(request, 'airplane/airplane_list.html', context)
Template:
{% extends 'base.html' %}
{% block title %} Airplane List {% endblock %}
{% block content %}
<center>
<div class="row">
{% for ap in ap_list %}
<div class="col-md-3">
<div class="card">
<div class="card-body">
<h1>
<center>
{{ ap.line_num }}
</center>
</h1>
<h3>
<p>Stall:<strong>{{ ap.stall }}</strong> VH:<strong>{{ ap.vh_num }}</strong> VZ:<strong>{{ap.vz_num }}</strong>
<p>MGR: {{ ap.owner }}</p>
<hr class="lead border border-dark">
<h1>{{ ap.id }}</h1>
{% if ap.status == "Avalible" %}
<p>Current Status:</p>
<p class="text-success">{{ ap.status }}</p>
{% else %}
<p>Current Status:</p>
<p class="text-danger">{{ ap.status }}</p>
{% endif %}
</h3>
<!-- Open Job counts -->
<div>
{% for open in open_jobs %}
{% if open.line_num_id == ap.id %}</p>
<p>Open Jobs: {{ open_jobs.count }}</p>
{% endif %}
{% endfor %}
{% for closed in closed_jobs %}
{% if closed.line_num_id == ap.id %}</p>
<p>Closed Jobs: {{ closed_jobs.count }}</p>
{% endif %}
{% endfor %}
</div>
<div class="lead border border-dark">
{% for comment in ap.ap_comments.all %}
{% if comment_id == ap_id %}
<p><strong>{{ comment.author }}</strong>: {{ comment.text }} # {{comment.created_at }}</p>
{% endif %}
{% endfor %}
</div>
</div>
</div>
</div>
{% endfor %}
</div>
</center>
{% endblock %}
OUTPUT:
Output
I want to display open and closed job counts per Airplane. Count of Open and Close jobs just add up to total jobs on Airplane.
As Kusko mentions in the comments, you can pass that number to the context. You can do so by doing something like this:
def Ap_linup(request):
context = {
'ap_list': Airplane.objects.all().filter(is_completed=False),
'open_jobs': Job.objects.all().filter(is_completed=False),
'closed_jobs': Job.objects.all().filter(is_completed=True),
'open_jobs_count': Job.objects.filter(is_completed=False).count(),
'closed_jobs_count': Job.objects.filter(is_completed=True).count()
}
Also, you don't need .all() because filter is sufficient.
and if you wanted to clean up the code a bit more so you don't have a lot of queries, you can declare variables before the context.
def Ap_linup(request):
open_jobs = Job.objects.filter(is_completed=False)
closed_jobs = Job.objects.filter(is_completed=True)
context = {
'ap_list': Airplane.objects.all().filter(is_completed=False),
'open_jobs': open_jobs,
'closed_jobs': closed_jobs,
'open_jobs_count': open_jobs.count(),
'closed_jobs_count': closed_jobs.count()
}
return render(request, 'airplane/airplane_list.html', context)
UPDATE:
To display this information in the template you can do this outside of your loop:
For closed jobs you just call the variable you set in the context
<p>Closed Jobs: {{ closed_jobs_count }}</p>
and for open jobs you would do the same thing
<p>Open Jobs: {{ open_jobs_count }}</p>
You no longer need to add a .count to the template because you already did the work on the backend. The value stored in closed_jobs_count and open_jobs_count is an number.
I have the following models:
class TutorialCategory(models.Model):
category_title = models.CharField(max_length=150)
category_summary = models.CharField(max_length=150)
category_slug = models.SlugField(default=1, blank=True)
class TutorialSeries(models.Model):
series_title = models.CharField(max_length=200)
series_maincategory = models.ForeignKey(
TutorialCategory, default=1, on_delete=models.SET_DEFAULT)
series_summary = models.CharField(max_length=200)
class Tutorial(models.Model):
tutorial_title = models.CharField(max_length=150)
tutorial_content = models.TextField()
tutorial_published = models.DateTimeField(
"date Published", default=datetime.now())
tutorial_series = models.ForeignKey(
TutorialSeries, default=1, on_delete=models.SET_DEFAULT)
tutorial_slug = models.SlugField(default=1, blank=True)
As shown above TutorialCategory is main category, TutorialSeries is sub category and Tutorial is sub-sub-category. I created a simple view that shows sub categories of main categories, but don't know how to show the sub-sub categories of sub category.
Please check out views.py and urls.py if you can improve its quality and if there is an easy and better way of doing it. Anyway, this is view:
def single_slug(request, single_slug):
matching_series = TutorialSeries.objects.filter(
series_maincategory__category_slug=single_slug)
series_urls = {}
for i in matching_series.all():
part_one = Tutorial.objects.filter(
tutorial_series__series_title=i.series_title).earliest("tutorial_published")
series_urls[i] = part_one.tutorial_slug
return render(request, 'tutorial/sub-category.html', context={
"tutorial_series": matching_series,
'part_ones': series_urls
})
urls here:
urlpatterns = [
path('', views.home_page, name='home'),
path('tutorial/<int:id>/', views.tutorial_detail, name='tutorial_detail'),
path('<single_slug>/', views.single_slug, name='single_slug'),
]
the template that shows sub-category of main category:
{% for tut, partone in part_ones.items %}
<div class="card">
<div class="card-body">
<h5 class="card-title">{{ tut.series_title }}</h5>
<p>{{ tut.series_summary }}</p>
Read more
</div>
</div>
{% endfor %}
Please help me how to do it and if you know any better way of doing it please let me know and help me. Thank you so much in advance.
edit: #ruddra
I changed views.py to this passing matching_series
def single_slug(request, single_slug):
matching_series = TutorialSeries.objects.filter(
series_maincategory__category_slug=single_slug)
series_urls = {}
for i in matching_series.all():
part_one = Tutorial.objects.filter(
tutorial_series__series_title=i.series_title).earliest("tutorial_published")
series_urls[i] = part_one.tutorial_slug
return render(request, 'tutorial/sub-category.html', context={
"matching_series": matching_series,
'part_ones': series_urls
})
and replaced the previous template with yours. template here:
{% for tutorial in matching_series %}
{% for sub_cat in tutorial.tutorialseries_set.all %}
{{ sub.series_title }}
{% for sub_sub_cat in sub.tutorial_set.all %}
{{ sub_sub_cat.tutorial_title }}
{% endfor %}
{% endfor %}
{% endfor %}
You can try like this:
{% for sub_cat in matching_series %}
{% for sub_sub_cat in sub_cat.tutorial_set.all %}
{{ sub_sub_cat.tutorial_title }}
{% endfor %}
{% endfor %}
Here I am assuming matching_series is being passed through context from view in single_slug. Then I am using backward relation between different models to fetch the data.
Explanation: Assuming there is object named tutorial_category which is instance of TutorialCategory. As there is ForeignKey from TutorialSeries to TutorialCategory, I can use tutorial_category.tutorialseries_set.all() or .filter() etc to fetch the tutorial series from tutorial_category object( As I am rendering it in template, I removed parenthesis after all). Similarly I fetch Tutorial from TutorialSeries.
I'm building a commenting system, which is working fine but i'm now trying to integrate voting. So I made another model to handle that and I tried to pair it using ForeignKey. Not too familiar with ForeignKey but i've looked at some other answers here to see how to render it in the template. I tried that using the nested for loop in my template below but {{ j.user }} doesn't render anything. Can anyone tell me what I'm doing wrong?
models.py
class Comment(models.Model):
destination = models.CharField(default='1', max_length=12, blank=True)
author = models.CharField(max_length=120, blank=True)
comment_id = models.IntegerField(default=1)
parent_id = models.IntegerField(default=0)
comment_text = models.TextField(max_length=350, blank=True)
timestamp = models.DateTimeField(default=timezone.now, blank=True)
def __str__(self):
return self.comment_text
class CommentScore(models.Model):
user = models.ForeignKey(User)
comment = models.ForeignKey(Comment)
upvotes = models.IntegerField(default=0)
downvotes = models.IntegerField(default=0)
views.py
...
comment_list = Comment.objects.filter(destination=id)
score = CommentScore.objects.all()
context = {
'score': score,
'comment_list': comment_list,
}
return render(request, 'article.html', context)
template
{% for i in comment_list %}
<div class='comment_div'>
<h3>{{ i.author }}</h3>
{% for j in comment_list.score_set.all %}
{{ j.user }} #nothing comes up
{% endfor %}
<p>{{ i.comment_text }}</p>
</div>
{% endfor %}
when using _set, the reverse relationship lookup, you must provide the full model name, you must also specify which instance this list of related models this "set" is for so it should be
{% for j in i.commentscore_set.all %}
{% empty %}
No scores found
{% endfor %}
You may also wish to set a related_name for the foreign key
comment = models.ForeignKey(Comment, related_name='scores')
...
{% for j in i.scores.all %}