How to retrieve data from one to many relations in django? - django

I am making my personal website using django 1.10
Here is models of skill app:
from __future__ import unicode_literals
from django.db import models
# Create your models here.
class Skill(models.Model):
name = models.CharField(max_length=256)
created_at = models.DateTimeField(auto_now=False, auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True, auto_now_add=False)
def __unicode__(self):
return self.name
def __str__(self):
return self.name
class Subskill(models.Model):
skill = models.ForeignKey(Skill, on_delete=models.CASCADE)
name = models.CharField(max_length=256)
link = models.CharField(max_length=256)
created_at = models.DateTimeField(auto_now=False, auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True, auto_now_add=False)
def __unicode__(self):
return self.name
def __str__(self):
return self.name
And view:
from django.shortcuts import render
from skill.models import Skill,Subskill
# Create your views here.
def home(request):
skill = Skill.objects.all()
subskill =Subskill.objects.all()
context = {'skills':skill,
'subskills':subskill}
return render(request, 'skill.html', context)
This is my template page:
skill.html
{% block skill %}
{% for subskill in subskills %}
{{subskill.skill.name}}
{{subskill.name}}
{% endfor %}
{% endblock skill %}
Let assume, there is a skill named web design which has two subskill named html and css.
I want to render in view page as like as skill name and it's two child name:
Web design
Html
CSS
But it renders as like Web design Html Web design CSS
Please help me about this issue.

You can do realted query on skill itself
https://docs.djangoproject.com/en/1.10/topics/db/queries/#backwards-related-objects
# example
skill_obj = Skill.objects.all()[0]
subskills = skill_obj.subskill_set.all()
Or in your case
def home(request):
skills = Skill.objects.all().prefetch_related('subskill_set') # optimizing
context = {'skills':skills}
return render(request, 'skill.html', context)
In template
{% for skill in skills %}
{{skill.name}}
{% for subskill in skill.subskill_set.all %}
{{subskill.name}}
{% endfor %}
{% endfor %}

Related

How to display A only a users entered data related in a foreignkey on detailview in django

I am building this simple quiz app. This app allows all users to submit an answer to an assignment in Docx format. I what that any time a user views the question on the DetailView page, if the user has already submitted a solution for that assignment, that solution should be shown on the DetailView page as well. Current I get is all that answers submitted by all users. I only want a user's answer to that assignment on the detailpage
this is my model.
class Assignment(models.Model):
title = models.CharField(max_length=120)
slug = models.SlugField(max_length=500)
course = models.ForeignKey(Course, on_delete=models.CASCADE)
class_or_level = models.ForeignKey(StudentClass, on_delete=models.CASCADE)
teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE)
Text = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
date_expire = models.DateTimeField()
def __str__(self):
return self.title
class Answer(models.Model):
slug = models.SlugField(max_length=500)
assignment = models.ForeignKey(Assignment, on_delete=models.CASCADE)
student = models.ForeignKey(User, on_delete=models.CASCADE)
file = models.FileField(upload_to='assignment')
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '{} - {} '.format(self.assignment, self.student)
Below is my view
class AssignmentSubmitView(DetailView):
model = Assignment
template_name = 'assignment_submit.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['student_answer'] = self.object.answer_set.all()
return context
Below is my filter on detailview template.
{% for answer in student_answer %}
{{ answer.file }}
{% endfor %}
You will need to first of all know the user that is accessing that page, so i presume you have a user model and an authentication system in place.
in the views
class AssignmentSubmitView(DetailView):
model = Assignment
template_name = 'assignment_submit.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['student_answer'] = self.object.answer_set.filter()#then filter and get the answer specific to that user here (depending on your user and Assignment models)
return context
and in your templates
{% if user.is_authenticated %}
{% if student_answer %}
{% for answer in student_answer %}
{{ answer.file }}
{% endfor %}
{% endif %}
{% endif %}

Post filter on the basis of tags in django taggit(package)

I just installed django taggit by following official documentation. Every things work fine but when i click on the tags it doesn't filter post containing that tags here is my code.
Code containing models.py file
..............
from taggit.managers import TaggableManager
..................
class Post(models.Model):
STATUS_CHOICES = ((DRAFT, _('draft')),
(PUBLISHED, _('published')))
author = models.ForeignKey(get_user_model(), verbose_name=_(
"Author"), on_delete=models.CASCADE, related_name='blog_posts')
title = models.CharField(_("Title"), max_length=200, unique=True)
slug = models.SlugField(_("Slug"), unique_for_date='publish')
status = models.IntegerField(
_('status'), db_index=True,
choices=STATUS_CHOICES, default=DRAFT)
tags = TaggableManager()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("blog:post_detail", kwargs={
"pk": self.pk
})
code contain views.py file
from django.views.generic import ListView
class PostListView(ListView):
model = Post
queryset = Post.published.all().order_by('-publish')
context_object_name = 'post_list'
template_name = "client/pages/blog_list.html"
paginate_by = 7
urls.py file
from .views import PostListView,
..........
path('tag/<slug:tag_slug>/', PostListView.as_view(), name='post_list_by_tag'),
..........
and in the templates file
<ul class="tags-inline">
<li>Tags:</li>
{% for tag in post_detail.tags.all %}
<li>
{{ tag.name }}
,
</li>
{% endfor %}
</ul>
You need to change your queryset to filter based on the tag. This is bringing back everything based on all()
queryset = Post.published.all().order_by('-publish')
I'm not sure how you filter on Taggit

How to display comments and it's replies in django templates?

I want to display comment and it's replies in the template. But there is an issue, every reply may have some other replies. The below snippet is my Comment and CommentReply model:
class Comment(models.Model):
author = models.ForeignKey(Profile, related_name="c_sender", on_delete=models.CASCADE, unique=False)
comment = models.CharField(max_length=500, unique=False)
created_date = models.DateTimeField(auto_now_add=True)
edited_date = models.DateTimeField(blank=True, null=True)
def __str__(self):
return self.comment
#property
def replys(self):
return CommentReply.objects.filter(comment_id=self)
class CommentReply(models.Model):
comment_id = models.ForeignKey(Comment, related_name='sender', on_delete=models.CASCADE)
reply_id = models.ForeignKey(Comment, related_name='reply', on_delete=models.CASCADE)
Updated:
Also I have a model for WorksComments that every comments that related to Work model saved there.
class WorkComment(models.Model):
work_id = models.ForeignKey(Work, on_delete=models.CASCADE, related_name='e_exercise', unique=False)
comment_id = models.ForeignKey(Comment, related_name='e_comment', unique=False)
The below snippet is my view:
comments = WorkComment.objects.filter(work_id=work).all()
return render(request, 'work.html', {'comments': comments})
My question is how to display comments and it's replies under it, and every reply may have some other replyies that I want to display them too.
First things first... put this in your bookmarks; https://ccbv.co.uk/
You're going to want a Detail View here I suspect in order to display the details of an instance.
Setup URLs...
from django.conf.urls import url
from work.views import WorkDetailView
urlpatterns = [
url(r'^(?P<id>[-\d]+)/$', WorkDetailView.as_view(), name='work-detail'),
]
And a view;
from django.views.generic.detail import DetailView
from django.utils import timezone
from work.models import Work
class WorkDetailView(DetailView):
model = Work
def get_context_data(self, **kwargs):
context = super(WorkDetailView, self).get_context_data(**kwargs)
context['comments'] = WorkComment.objects.filter(work_id=self.object.id).all()
return context
Then a simple view might be work/work_detail.html:
<h1>{{ object.title }}</h1>
<p>{{ object.content }}</p>
<h2>Comments</h2>
{% for comment in comments %}
{{ comment }}
{% endfor %}

Joining two tables django newbie qustion

mysqllite table joining in django is new to me. I can query just fine on one table. and somewhat at joining via just raw mysql. What i need is an example of how to code to tables together Ie below the models and the first qustion on my project is to find all the teams that are in Atlantic confrence
I have
this in view
"atlanticsoccer": League.objects.filter(name__contains="atlantic")
this in html
<h5>Question 1</h5>
{% for whatever in atlanticsoccer %}
<li>{{whatever.name}}</li>
<li></li>
{% endfor %}
</ol>
which gives me all my Atlantic conference leauges. But i can't seem to find an example of how to join the teams by id . I have linked below the models view If i can get an example of how to do the first I can figure out the html. Thanks in advance for helping a new coder.
Models.py
from django.db import models
class League(models.Model):
name = models.CharField(max_length=50)
sport = models.CharField(max_length=15)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Team(models.Model):
location = models.CharField(max_length=50)
team_name = models.CharField(max_length=50)
league = models.ForeignKey(League, related_name="teams")
class Player(models.Model):
first_name = models.CharField(max_length=15)
last_name = models.CharField(max_length=15)
curr_team = models.ForeignKey(Team, related_name="curr_players")
all_teams = models.ManyToManyField(Team, related_name="all_players")
views.py
from django.shortcuts import render, redirect
from .models import League, Team, Player
from . import team_maker
def index(request):
context = {
"leagues": League.objects.all(),
"teams": Team.objects.all(),
"players": Player.objects.all(),
"atlanticsoccer": League.objects.filter(name__contains="atlantic")
}
return render(request, "leagues/index.html", context)
def make_data(request):
team_maker.gen_leagues(10)
team_maker.gen_teams(50)
team_maker.gen_players(200)
return redirect("index")
index.html
<h5>Question 1</h5>
{% for whatever in atlanticsoccer %}
<li>{{whatever.name}}</li>
<li></li>
{% endfor %}
</ol>
First get all teams that have a league with a name of "atlantic":
atlanticsoccer = Team.objects.filter(league__name__contains='atlantic')
Then iterate through them in your template and print whatever you want:
<ul>
{% for team in atlanticsoccer %}
<li>{{team.location}}</li>
<li>{{team.team_name}}</li>
<li>{{team.league.name}}</li>
<li>{{team.league.sport}}</li>
{% endfor %}
</ul>

How to pass multiple app's models in one views? [django]

Hei there,
I'm having difficulties passing two app models in one views. I have 2 apps :
Post
Author
What I expect is, I want to display Author's avatar in the Post views, so I can include it in posts loop.
Author models.py :
class Author(models.Model):
avatar = models.ImageField(upload_to='images/%Y/%m/%d', verbose_name=u'Author Avatar', validators=[validate_image], blank=True, null=True)
user = models.OneToOneField(User, on_delete=models.CASCADE)
location = models.CharField(max_length=30, blank=True)
...
Post views.py :
from app_author.models import Author
class PostList(ListView):
model = Post
template_name = 'app_blog/blog_homepage.html'
context_object_name = 'post_list'
paginate_by = 9
def get_context_data(self, **kwargs):
context = super(PostList, self).get_context_data(**kwargs)
context['post_hot'] = Post.objects.filter(misc_hot_post = True).order_by('-misc_created')[:1]
context['post_list'] = Post.objects.filter(misc_published = True).order_by('-misc_created')
context['author'] = Author.objects.all() # No need this line
return context
When I called something like this in templates, it doesn't work. The {{ author.avatar }} not showing :
{% for post in post_list %}
<ul>
<li>{{ post.title }}</li> # This is works just fine
<li>{{ author.avatar }}</li> # This does not work at all
<ul>
{% endfor %}
My Posts app urls.py :
from . import views
from django.conf import settings
from app_blog.views import PostList, PostDetailView
from django.conf.urls import include, url
from django.conf.urls.static import static
urlpatterns = [
url(r'^$', views.PostList.as_view(), name='post-list'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Any help would be greatly appreciated!
Thank you in advance!
Regards
--- UPDATE ---
Here is my Post models.py
import datetime
from django import forms
from django.db import models
from django.conf import settings
from autoslug import AutoSlugField
from django.forms import ModelForm
from app_author.models import Author
from taggit.managers import TaggableManager
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.template.defaultfilters import slugify
# CUSTOM FILE SIZE VALIDATOR
def validate_image(fieldfile_obj):
filesize = fieldfile_obj.file.size
megabyte_limit = 5
if filesize > megabyte_limit*1024*1024:
raise ValidationError("Max file size is %sMB" % str(megabyte_limit))
class Category(models.Model):
# PRIMARY DATA
id = models.AutoField(primary_key=True)
category_name = models.CharField(max_length=200, verbose_name=u'Category Name', blank=False, null=False)
def __str__(self):
return str(self.category_name)
class Post(models.Model):
# PRIMARY DATA
post_image = models.ImageField(upload_to='images/%Y/%m/%d', verbose_name=u'Post Featured Image', validators=[validate_image], blank=True, null=True)
post_author = models.ForeignKey(Author, related_name="user_posts", null=True, blank=True)
post_title = models.CharField(max_length=200, verbose_name=u'Post Title', blank=False, null=False)
post_sub_title = models.CharField(max_length=200, verbose_name=u'Post Sub-Title', blank=False, null=False)
post_category = models.ForeignKey('Category', verbose_name=u'Post Category', on_delete=models.CASCADE)
post_content = models.TextField()
post_tags = TaggableManager()
slug = AutoSlugField(populate_from='post_title')
# MISC
misc_created = models.DateTimeField(default=datetime.datetime.now, null=True, blank=True)
misc_modified = models.DateTimeField(default=datetime.datetime.now, null=True, blank=True)
misc_hot_post = models.BooleanField(default=False)
misc_published = models.BooleanField(default=False)
def __str__(self):
return str(self.post_title)
#models.permalink
def get_absolute_url(self):
return 'app_blog:post', (self.slug,)
Thank you
--- UPDATE 2 ---
SOLVED
#Gagik & #Daniel answer sloved my problem. I just have to use this tag instead :
{{ post.post_author.avatar }}
I did not change any code above. Except I dont need this line :
context['author'] = Author.objects.all()
Thank you
You need to related Author and Post models to each other by ForeignKey file, like:
class Post (models.Model):
author = models.ForeignKey(Author)
Then when you can access to your avatar through post.author.
Updated:
Updating answer after question updated.
I think you need to update your template as follows. use post.post_author.avatar to access the avatar you need:
{% for post in post_list %}
<ul>
<li>{{ post.title }}</li> # This is works just fine
<li>{{ post.post_author.avatar }}</li> # This does not work at all
<ul>
{% endfor %}
Considering this please note that you don't need to search Author's desperately in your view. So you don't need to have following line:
context['author'] = Author.objects.all() # This is where I expect the magic is
Because when you have ForeignKey then you already have access to Author through post object.
Gagik and JF's answers should have been enough for you to work out what to do. Your foreign key is called "post_author", so that's what you should use in the template:
{{ post.post_author.avatar }}
There's no need for you get all the authors and pass them to the template in your view as you are doing.