Access Django's class model and display on template - python

I am new to django and is working on my pet project. I am having a bit of problem accessing the data from one of my classes in models.py
models.py
class Team_Region(models.Model):
name = models.CharField(max_length=50)
# String representation
def __str__(self):
return self.name
class Team_Name(models.Model):
t_name = models.CharField(max_length=100)
logo = models.ImageField(upload_to='team_logos', blank=True)
region_member = models.ForeignKey(Team_Region, related_name='regions')
def __str__(self):
return self.t_name + ' - ' + str(self.region_member)
class Team_Member(models.Model):
mem_name = models.CharField(max_length=100)
position = models.CharField(max_length=50)
member_of_team = models.ForeignKey(Team_Name, related_name='teams')
def __str__(self):
return self.mem_name + ' - ' + self.position + ' - ' + str(self.member_of_team)
views.py
# Display regions in list
class TeamRegionListView(ListView):
context_object_name = 'regions_list'
model = Team_Region
template_name = 'dota_teams/team_regions_list.html'
# Display all teams associated to the region
class TeamRegionDetailView(DetailView):
context_object_name = 'region_teams'
model = Team_Region
template_name = 'dota_teams/team_regions_detail.html'
class MemberDetailView(DetailView):
context_object_name = 'team_members'
model = Team_Name
template_name = 'dota_teams/member_detail.html'
urls.py
url(r'^$', views.TeamRegionListView.as_view(), name='all_regions'),
url(r'^(?P<pk>\d+)/$', views.TeamRegionDetailView.as_view(), name='region_teams'),
url(r'^(?P<pk>\d+)/(\d+)/$', views.MemberDetailView.as_view(), name='member_details'),
UPDATE
team_regions_list.html
{% block body_block %}
<div class="row">
{% for region in regions_list %}
<div class="col-xs-12 col-lg-4">
<a href="{{ region.id }}" class="thumbnail" style="width: 350px; height:350px">
<h4 style="text-align: center; margin-top: 150px"> {{ region.name }} </h4>
</a>
</div>
{% endfor %}
</div>
{% endblock %}
team_regions_detail.html
{% block body_block %}
<div class="row">
{% for team in region_teams.regions.all %}
<div class="col-xs-12 col-lg-4">
<a href="{{ team.id }}" class="thumbnail">
<img style="width: 100px; height:90px" src="{{ team.logo.url }}" alt="Image not found.">
<div class="caption">
<h4 style="text-align:center">{{ team.t_name }}</h4>
</div>
</a>
</div>
{% endfor %}
</div>
{% endblock %}
I'm not sure how to access the mem_name and position variables under the Team_Member class. In my views.py, if I use the model Team_Name, the ID is not properly assigned to the region and team. I have tried accessing the Team_Member by using a For loop from Team_Region and use the 'related_name' of Team_Name then access the 'related_name' of Team_Member but it won't work either (e.g. {% for member in regions_list.regions.teams.all %} ). I'm a bit loss on this.
Any suggestions please?
TIA

Based on your models, it has the relationship:
Team_Region --> has many Team_Name
Team_Name --> has many Team_Member
you have already defined the foreign keys with related_name, if you access the Team_Member from Team_Region, you have to for loop the regions_list first, then use the related_name regions to get the team names, after that for loop all the teams, use the related_name teams to get the team members. In your template team_regions_list.html, like this:
{%for rl in regions_list%}
{%for tn in rl.regions.all %}
{{tn.teams.all}}
{% endfor %}
{% endfor %}
Update:
in your views.py, the modal is not correct for class TeamRegionDetailView and MemberDetailView, change to:
# Display regions in list
class TeamRegionListView(ListView):
context_object_name = 'regions_list'
model = Team_Region
template_name = 'dota_teams/team_regions_list.html'
# Display all teams associated to the region
class TeamRegionDetailView(DetailView):
context_object_name = 'region_teams'
model = Team_Name
template_name = 'dota_teams/team_regions_detail.html'
class MemberDetailView(DetailView):
context_object_name = 'team_members'
model = Team_Member
template_name = 'dota_teams/member_detail.html'
Use region_teams.teams.all instead of region_teams.regions.all, change your team_regions_detail.html to :
<div class="row">
{% for team in region_teams.teams.all %}
<div class="col-xs-12 col-lg-4">
<a href="{{ team.id }}" class="thumbnail">
<img style="width: 100px; height:90px" src="{{ region_teams.logo.url }}" alt="Image not found.">
<div class="caption">
<h4 style="text-align:center">{{ team.t_name }}</h4>
</div>
</a>
</div>
{% endfor %}
</div>
Update 2:
I believe that you manage your upload files incorrectly, refer to official doc:
By default, Django stores files locally, using the MEDIA_ROOT and
MEDIA_URL settings.
in your project settings.py file, add them:
MEDIA_ROOT = os.path.join(BASE_DIR,'media')
MEDIA_URL = '/media/'
and in your project urls.py file, add:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
After that the template can access your uploaded images with (/media/team_logos/test.png), eg:
http://127.0.0.1:8000/media/team_logos/test.png

I'd like to thank Tiny.D for the idea on the solution.
I updated my views.py
from django.views.generic import ListView, DetailView
from .models import Team_Region, Team_Name, Team_Member
#Display regions in list
class TeamRegionListView(ListView):
context_object_name = 'regionlist'
model = Team_Region
template_name = 'dota_teams/team_region_list.html'
#Display teams associated to the region
class TeamRegionDetailView(DetailView):
context_object_name = 'regiondetail'
model = Team_Region
template_name = 'dota_teams/team_region_detail.html'
#Display members of each team
class TeamDetailView(DetailView):
context_object_name = 'teamdetail'
model = Team_Region
template_name = 'dota_teams/team_detail.html'
urls.py
url(r'^$', views.TeamRegionListView.as_view(), name='region_list'),
url(r'^(?P<pk>\d+)/$', views.TeamRegionDetailView.as_view(), name='region_detail'),
url(r'^(?P<pk>\d+)/(\d+)/$', views.TeamDetailView.as_view(), name='member'),
The logic of the team_region_list.html and team_region_detail.html are the same to my post above.
team_detail.html
{% block body_block %}
<div class="row">
{% for member in teamdetail.regions.all %}
{% for member_detail in member.teams.all %}
<h4>{{ member_detail.mem_name }}</h4>
{% endfor %}
{% endfor %}
</div>
{% endblock %}
For the team_detail.html, I just need to perform a nested loop just what Tiny.D mentioned. Everything is working now. Thanks.

Related

The 'poster' attribute does not have a file associated with it"

The following error occurs
The 'poster' attribute does not have a file associated with it
I don't quite understand what it may be related to and how to fix it
I tried to change the url value, but nothing worked.
html
<div class="container" style="grid-template-columns: repeat(auto-fill, 300px);">
for serial in serials %}
<div class="item">
<img src="{{ serial.poster.url }}" class="img-fluid" alt="">
<p>
{{ serial.title }}
</p>
</div>
endfor %}
</div>
views.py
class SerialDetailView(View):
def get(self, request):
serials = Serials.objects.all()
genres = Genre.objects.all()
return render(request, "serials/single_serial.html", {"serials": serials, "genres": genres})
urls.py
urlpatterns = [
path('register/', views.Register.as_view(), name='register'),
path('reg/', views.Reg.as_view(), name='reg'),
path("serials_list/", views.SerialsView.as_view(), name='serials_list'),
path("add/", views.AddView.as_view(), name='add'),
path("single_serial/", views.SerialDetailView.as_view(), name='single_serial'),
path("<slug:slug>/", views.SingleSerial.as_view(), name='detail_serial'),
path("actor/<int:id>/", views.ActorView.as_view(), name='actor_detail'),
]
My models
class Serials(models.Model):
title = models.CharField('Name',max_length=100)
description = models.CharField('Description', max_length= 200)
poster = models.ImageField('Poster', upload_to='serials/')
date = models.DateField('Date')
country = models.CharField('Страна',max_length=100)
actors = models.ManyToManyField(Actor, verbose_name='actors', related_name='actor')
genre = models.ManyToManyField(Genre, verbose_name='genres')
category = models.ForeignKey(Category, verbose_name='category', on_delete=models.SET_NULL, null=True)
url = models.SlugField(unique=False)
link = models.URLField(max_length=200, blank=True)
Because you are trying to display the image of one of the serials while you did not choose an image for it.
First, choose an image for all serials poster or use the following code:
<div class="container" style="grid-template-columns: repeat(auto-fill,
300px);">
for serial in serials %}
<div class="item">
{% if serial.poster %}
<img src="{{ serial.poster.url }}" class="img-fluid"
alt="">
{% endif %}
<p>
{{ serial.title }}
</p>
</div>
{% endfor %}
</div>

Django display data from two different models

I have two seperated models. One with two text fields and one for multiple images. Now I want to display the entire data in one html div. What do I have to change in the projects view and in projects.html?
models.py
class Project(models.Model):
title = models.CharField(max_length=200)
describtion = models.TextField(null=True, blank=True)
class ProjectImage(models.Model):
project = models.ForeignKey(Project, on_delete=models.CASCADE)
image = models.FileField(upload_to="products/")
forms.py
class ProjectForm(forms.ModelForm):
class Meta:
model = Project
fields = ['title', 'describtion']
class ProjectImageForm(forms.ModelForm):
class Meta:
model = ProjectImage
fields = ['image']
widgets = {
'image': ClearableFileInput(attrs={'multiple': True}),
}
views.py
def createProject(request):
form = ProjectForm()
form2 = ProjectImageForm()
if request.method == 'POST':
form = ProjectForm(request.POST)
form2 = ProjectImageForm(request.POST, request.FILES)
images = request.FILES.getlist('image')
if form.is_valid() and form2.is_valid():
title = form.cleaned_data['title']
describ = form.cleaned_data['describtion']
project_instance = Project.objects.create(
title=title, describtion=describ)
for i in images:
ProjectImage.objects.create(project=project_instance, image=i)
context = {'form': form, 'form2': form2}
return render(request, 'projects/project_form.html', context)
def projects(request):
projects = Project.objects.all()
context = {"projects":projects}
return render(request, 'projects/projects.html', context)
projects.html
{% for project in projects %}
<div class="column">
<div class="card project">
<img class="project__thumbnail" src="{{project.image.url}}" alt="project thumbnail" />
<div class="card__body">
<h3>{{project.title}}</h3>
<h2>{{project.describtion}}</h2>
</div>
</a>
</div>
</div>
{% endfor %}
You don't need to change anything.
You should be able to access the reverse with project.project_image_set attribute in the template:
<div class="card__body"
<h3>{{project.title}}</h3>
<h2>{{project.describtion}}</h2>
{% for image in project.project_image_set.all %}
{{ image.image }}
{% endfor %}
</div>
Docs: https://docs.djangoproject.com/en/4.0/topics/db/examples/many_to_one/
I don't really understand the question here but i see a problem in your template considering you are using foreign key in ProjectImage. And update the question
{% for project in projects %}
<div class="column">
<div class="card project">
{% for j in project.projectimage_set.all %}
<img class="project__thumbnail" src="{{j.image.url}}" alt="project thumbnail" />
{% endfor %}
<div class="card__body">
<h3>{{project.title}}</h3>
<h2>{{project.describtion}}</h2>
</div>
</a>
</div>
</div>
{% endfor %}
I would change FileField to ImageField and add function:
#property
def get_photo_url(self):
if self.image and hasattr(self.image, 'url'):
return self.image.url
else:
return ''
If createProject function works( I would rename it to create_project) then in projects.html:
{% for project in projects %}
<div class="column">
<div class="card project">
<div class="card__body">
<h3>{{project.title}}</h3>
<h2>{{project.describtion}}</h2>
{% for img in project.projectimage_set.all %}
<img class="project__thumbnail" src="{{img.get_photo_url}}" alt="project thumbnail" />
{% endfor %}
</div>
</a>
</div>
</div>
{% endfor %}

i want to display the list of pruducts based on the choice of the category chosing -django

so i want to khow what i have to add in the urls.py and in the views.py to add this functionnality: if i click in one of this categories here my categories display some products based on the category chosen.
and this the models.py
class Product(models.Model):
name=models.CharField(max_length=200,null=True)
price=models.DecimalField(max_digits=7,decimal_places=2)
digital=models.BooleanField(default=False,null=True,blank=True)
image=models.ImageField(blank=True,null=True,upload_to ='images/',default="images/default.jpg")
categories = models.ForeignKey(Category,on_delete=models.CASCADE,blank=True, null=True)
def __str__(self):
return self.name
#property
def imageURL(self):
if self.image and hasattr(self.image, 'url'):
return self.image.url
else:
return '/static/images/default.png'
class Category(models.Model):
name = models.CharField(max_length=50)
slug = models.SlugField(max_length=50, unique=True,
help_text='Unique value for product page URL, created from name.')
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'categories'
ordering = ['-created_at']
verbose_name_plural = 'Categories'
def __unicode__(self):
return self.name
and this is the template :
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<form method="get" action="">
{% for c in active_categories %}
<a class="dropdown-item" href='#'>{{ c.name }}</a>
{% endfor %}
<a class="dropdown-item" href="#">something else</a>
</form>
</div>
This is simplest way. You can change code as per requirement.
urls.py
from . import views # import views.py file
urlpatterns = [
path('product_list/<id>', views.product_list, name='product_list'),
]
views.py
def product_list(request, id):
products = Product.objects.filter(categories__pk=id)
context = {
'products': products,
}
return render(request, 'product_list.html', context)
link template (Check the change in link)
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<form method="get" action="">
{% for c in active_categories %}
<a class="dropdown-item" href="{% url 'product_list' id=c.pk %}">{{ c.name }}</a>
{% endfor %}
<a class="dropdown-item" href="#">something else</a>
</form>
</div>
product_list.html
Your regular html things +
{% for product in products %}
<p>{{ product.name }}</p>
<p>{{ product.price }}</p>
{% empty %} # in case there is no product in this category
<p>No product available for this category</p>
{% endfor %}
I hope this will help. Please comment if get any error.
If you products to load without refreshing the page, you can use ajax. Reply if need that.
You can try this:
views.py
def my_view(request):
category_id = request.GET.get('category_id')
context = {}
if category_id:
products = Product.objects.filter(categories__id=category__id)
context["products"] = products
return render(request, 'template', context)
template
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<form method="get" action="">
{% for c in active_categories %}
<a class="dropdown-item" href='?category_id={{ c.id }}'>{{ c.name }}</a>
{% endfor %}
<a class="dropdown-item" href="#">something else</a>
</form>
</div>

The variables for my Job model is not showing

I have created a Job model that contains Member and Manager info. It looks great imo. I created a class based view that translates the job if the user has one. Right now it's not showing. It just shows as a blank with an empty image file. I don't know what I did wrong or if I mistakenly used the wrong variables in the html file.
Here's my views.py:
from django.shortcuts import render
from django.views.generic import ListView, CreateView
from .models import Job
from profiles.models import User
# Create your views here.
class jobs(ListView):
model = Job
template_name = 'users/user_jobs.html'
context_object_name = 'jobs'
def get_queryset(self):
return Job.objects.filter(member__member=self.request.user)
class createjob (CreateView):
model = Job
fields = ['member','title', 'description', 'file'
My Models.py:
from django.db import models
from profiles.models import User
# Create your models here.
class Points (models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
points = models.IntegerField(default=0, null=False)
def __str__(self):
return self.user.username
class Profile (models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.png',upload_to='profile_pics')
def __str__(self):
return f'{self.user.username}Profile'
class Manager (models.Model):
name = models.CharField(max_length=30, blank=True, null=True)
manager = models.ForeignKey(User,on_delete=models.CASCADE)
def __str__(self):
return self.name
class Member (models.Model):
name = models.CharField(max_length=30, blank=True, null=True)
manager = models.ForeignKey(Manager, on_delete=models.CASCADE)
member = models.ForeignKey(User,on_delete=models.CASCADE)
def __str__(self):
return self.name
class Job (models.Model):
manager = models.OneToOneField(Manager, on_delete=models.CASCADE)
member = models.OneToOneField(Member, on_delete=models.CASCADE)
title = models.CharField(max_length=30, blank=False, null=False)
description = models.TextField()
datePosted = models.DateTimeField (auto_now = True)
file = models.FileField(null=True, blank=True,upload_to='job_files')
def __str__(self):
return self.title
And user_jobs.html:
{% extends "profiles/base.html" %}
{% block content %}
<article class="media content-section">
<img class="rounded-circle article-img"src="{{ jobs.manager.profile.image.url}}">
<div class="media-body">
<div class="article-metadata">
<a class="mr-2" href="#">{{ objects.job.Manager }}</a>
<small class="text-muted">{{jobs.datePosted|date:"F d, Y" }}</small>
</div>
<h2><a class="article-title" href="#">{{ jobs.title }}</a></h2>
<p class="article-content">{{ jobs.description }}</p>
</div>
</article>
{% if is_paginated %}
{% if page_obj.has_previous %}
<a class="btn btn-outline-info mb-4"href="?page=1"> First</a>
<a class="btn btn-outline-info mb-4"href="?page={{ page_obj.previous_page_number }}"> Previous</a>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<a class="btn btn-outline-info mb-4"href="?page={{ num }}"> {{ num }}</a>
{% elif num > page.obj.number|add:'-3' or num < page.obj.number|add:'3' %}
<a class="btn btn-outline-info mb-4"href="?page={{ num }}"> {{ num }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a class="btn btn-outline-info mb-4"href="?page={{ page_obj.next_page_number }}"> Next </a>
<a class="btn btn-outline-info mb-4"href="?page={{ page_obj.paginator.num_pages }}"> Last </a>
{% endif %}
{%endif%}
{% endblock content %}
TIA for the help guys.
you have to loop through the object list output in your list template to see the out put
{% for object in jobs %}
{{ object.title }}
{% endfor %}

Django Template filtering

I am trying to create a website where you can view different "ranks" and the people within them. I have gotten it to create the ranks into there own Collapsable Panels, as I am using Bootstrap 3, but I am unable to list the Users who have that rank. Please help.
#team.html template
<div class="container">
<div class="col-md-2">
<div class="panel-group" id="accordion">
{% for rank in Rank_list %}
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#collapse{{rank.rank_num}}">
{{ rank.rank_name }}s
</a>
</h4>
</div>
<div id="collapse{{rank.rank_num}}" class="panel-collapse collapse in">
<div class="panel-body">
{% for name in User_list %}
<li>
<p>{{name}}</p>
</li>
{% endfor %}
</div>
</div>
</div>
{% endfor %}
</div>
</div>
#views.py
class team(generic.ListView):
template_name = 'main/team.html'
context_object_name = 'Rank_list'
context_object_name2 = 'User_list'
def get_queryset(self):
return Rank.objects.order_by('rank_num')
def get_queryset2(self):
return User.objects.order_by('name')
#models.py
class Rank(models.Model):
rank_name = models.CharField(max_length=200)
rank_num = models.IntegerField(default=0)
def __str__(self): # __unicode__ on Python 2
return self.rank_name
class User(models.Model):
rank = models.ForeignKey(Rank)
name = models.CharField(max_length=200)
def __str__(self): # __unicode__ on Python 2
return self.name
You need to add a related_name to the foreign key. Like this:
rank = models.ForeignKey(Rank, related_name='users')
Then the users can be accessed in a loop like this:
{% for user in rank.users.all %}
{{ user }}
{% endfor %}
For each Rank object, you can reverse the relationship and get all of the Users related to that Rank
# models.py
# - Use `related_name` for making relationship that are easy to read and follow
# - https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.related_name
class User(...):
rank = models.ForeignKey(Rank, related_name="users")
# view.py
# - Use prefetch_related allows us to cut down our queries when iterating as we do an up-front join
# - https://docs.djangoproject.com/en/dev/ref/models/querysets/#prefetch-related
...
def get_queryset(self):
return Rank.objects.prefetch_related('users')('rank_num')
# template.py
{% for rank in Rank_List %} # You shouldn't capitalise your template variables
{% for user in rank.users.all %}
{{ user }}
{% endfor %}
{% endfor %}
Finally, you should use the built-in User model that django's auth module provides

Categories