How to select an instance of a model from a queryset django? - python-3.x

I am creating a project for hosting cricket tournaments. I have created 3 apps in it: home, tournament and team. After adding a tournament, when entering the tournament's detail view, I can add a team to the tournament. My Team model has a ForeignKey to my Tournament model, and my Tournament model has a ForeignKey to my User model(built-in django user model). When creating a team, I want to save the team for a particular tournament. I don't understand how to access the exact tournament and save the team for that tournament only.
My tournament detail html:
{% extends 'menu.html' %}
{% block content %}
<div class="row">
<div class="col-8">
<table class="table table-bordered table-hover">
<tr>
<th scope="col">Match between</th>
<th scope="col">Winner</th>
</tr>
{% for match in match_list %}
<tr>
<td>
{{ match.team1.name }} vs {{ match.team2.name }}
</td>
<td>
{% if match.winner %}
{{ match.winner.name }}
{% else %}
TBD
{% endif %}
</td>
</tr>
{% endfor %}
</table>
</div>
<div class="col-4">
{% if teamscount < tournament.no_of_teams %}
<button class="btn btn-primary" onclick="window.location.href='{% url 'teams:addteam' %}'">Add Team</button>
{% endif %}
</div>
</div>
{% endblock content %}
My urls.py file in tournament app:
from django.urls import path, include
from . import views
app_name='tournaments'
urlpatterns = [
path('all/', views.TournamentListView.as_view(), name='all'),
path('create/', views.TournamentCreateView.as_view(), name='create'),
path('view/<int:pk>/', views.TournamentDetailView.as_view(), name='detail'),
]
My urls.py file in teams app:
from django.urls import path
from . import views
app_name="teams"
urlpatterns = [
path('new/', views.TeamCreateView.as_view(), name="addteam"),
]
My views.py file in teams app:
from django.shortcuts import render
from django.views.generic import CreateView
from .models import Team
from django.urls import reverse_lazy
from tournament.models import Tournament
class TeamCreateView(CreateView):
model = Team
fields = ['name', 'no_of_players',]
success_url = reverse_lazy('tournaments:all')
success_message = "Tournament Created!!"
def get_form(self):
form = super().get_form()
return form
def form_valid(self, form):
print('form_valid called')
object = form.save(commit=False)
object.tournament = Tournament.objects.filter(user = self.request.user)
object.save()
return super(TeamCreateView, self).form_valid(form)
My create team html file:
{% extends 'menu.html' %}
{% load crispy_forms_tags %}
{% block content %}
{% load bootstrap4 %}
{% bootstrap_css %}
{% bootstrap_javascript jquery='full' %}
{{ form.media }}
<form
action="{% url 'teams:addteam' %}"
method="post"
id="upload_form"
enctype="multipart/form-data"
>
{% csrf_token %} {{ form|crispy }}
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Create</button>
<input class="btn btn-danger" type="submit" onclick="window.location='{% url 'tournaments:all' %}' ; return false;" value="Cancel" />
</div>
</form>
{% endblock content %}
How can I save this team to the specific tournament model, or do I need to change the way I've designed the functions and classes?

For what i understood your models have the following design:
class Tournament(models.Model):
name = models.CharField(max_length=50)
user = models.ForeignKey(
get_user_model(),
on_delete=models.CASCADE
)
def __str__(self):
return self.name
class Team(models.Model):
name = models.CharField(max_length=50)
tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE)
def __str__(self):
return self.name
So, if you want to save a Team instance to a specific Tournament, you need to do the following:
# Grab the tournament instance in a variable (I recommend to use the id instead of the user. This is probably better, unless the user is unique per tournament, if not .get() will throw an error )
tournament = Tournament.objects.get(user=user)
# Then create your Team object like this
Team.objects.create(name='super team', tournament=tournament)
One of the problems i see is that you are using 'filter' alone to try to get an instance. 'Filter' returns a QuerySet. You have many choices to return a specific instance after using 'filter', you can do .filter().first() or .filter()[0] (or any number) and there are more

Related

Can't show specific model field in my HTML template

On my main page i want to show a category just like {{ post.body }} but instead {{ post.body }} would be {{ post.category }} here.
{% extends "base.html" %}
{% block title %}Articles{% endblock title %}
{% block content %}
{% for post in post_list %}
<div class="card">
<div class="card-header">
<span class="font-weight-bold">{{ post.title }} |
</span> ·
<span class="text-muted">by {{ post.author }} |
{{ post.created_at }}</span>
</div>
<div class="card-body">
<!-- Changes start here! -->
<p>{{ post.body }}</p>
<p>{{ post.category }}</p>
Edit |
Delete |
Category
</div>
<div class="card-footer">
{% for comment in post.comment_set.all %}
<p>
<span class="font-weight-bold">
{{ comment.author }} ·
</span>
{{ comment }}
</p>
{% endfor %}
</div>
<!-- Changes end here! -->
</div>
<br />
{% endfor %}
{% endblock content %}
but cannot to figure out how. But cannot figure out how.
Here is my models
from django.conf import settings
from django.db import models
from django.urls import reverse
class Category(models.Model):
name = models.CharField(max_length=255)
def __str__(self):
return (self.name)
def get_absolute_url(self):
return reverse("home")
class Post(models.Model):
title = models.CharField(max_length=255)
body = models.TextField()
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE,)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
category = models.ManyToManyField(Category, related_name='categories')
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("post_detail", kwargs={"pk": self.pk})
class Comment(models.Model):
article = models.ForeignKey(Post, null=True, blank=True, on_delete=models.CASCADE)
comment = models.CharField(max_length=140)
author = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE,)
def __str__(self):
return self.comment
def get_absolute_url(self):
return reverse("post_list")
Thanks in advance
Added {{ post.category }} in here
{% extends "base.html" %}
{% block title %}Articles{% endblock title %}
{% block content %}
{% for post in post_list %}
<div class="card">
<div class="card-header">
<span class="font-weight-bold">{{ post.title }} |
</span> ·
<span class="text-muted">by {{ post.author }} |
{{ post.created_at }}</span>
</div>
<div class="card-body">
<!-- Changes start here! -->
<p>{{ post.body }}</p>
<p>{{ post.category }}</p>
Edit |
Delete |
Category
</div>
<div class="card-footer">
{% for comment in post.comment_set.all %}
<p>
<span class="font-weight-bold">
{{ comment.author }} ·
</span>
{{ comment }}
</p>
{% endfor %}
</div>
<!-- Changes end here! -->
</div>
<br />
{% endfor %}
{% endblock content %}
expected to see a category instead got post.category.None
To show the category in the HTML just like a property, you can add a property method in the model class and use it HTML, like this:
class Post(models.Model):
...
#property
def categories(self):
return ', '.join([x.name for x in self.category.all()]
Then use it template like:
{{ post.categories }}
Alternatively as it is a ManyToMany field, you can iterate through it in the template and render the categories:
{{ for c in post.category }} {{ c.name }} {% if not forloop.last %}, {% endif %} {{ endfor }}
Explanation of property method: property method allows you to convert a function to an attribute of the object of that class. self in the property method refers to itself (or the object itself). using self.category.all(), you are accessing the manytomany relation between Post and Category class. I am running a loop and access each of the Category objects connected to the Post object (the main object which are using in the template/html) and I am joining the names of the Category objects' names to form a comma separated string.

Django NoReverseMatch Error on Update and Delete Buttons

Thank you for reading my question, and for your help.
I wrote a simple CRUD app, and used django-tables2 module to make my tables look pretty and more robust. I am using django 3.2, python 3.8.5, django_tables2 2.3.4.
I can enter a query in the search bar on the home.html page and lists the returned results from a postgresql on the search_results.html page. On the search_results page, I have buttons next to each returned row with edit and delete options, when I hover over update buttons it points to url for localhost:8955/update/7887 or localhost:8955/delete/7887 for the delete button, of course the last four digits are unique to the returned rows, however when I click on the update or delete button I get a NoReverseMatch error. I am at my wits end what is causing the edit and delete buttons not to work, your help and assistance is very much appreciated it.
Image with the returned results with the update and delete button
tables.py
from .models import EsgDatabase
from django.urls import reverse_lazy
from django.contrib.auth.models import User as user
class EsgListViewTable(tables.Table):
class Meta:
model = EsgDatabase
template_name = "django_tables2/bootstrap-responsive.html"
fields = ('id','role', 'hq','system','market','state','zone','arrisseachangezone','xgsystem','xgzonecode','fto','xocnoc','snowticketassignment',)
if user.is_authenticated:
edit = TemplateColumn(template_name='update.html')
delete = TemplateColumn(template_name='delete.html')
app urls.py
from django.urls import path, include
from .views import HomePageView, SearchResultsView, EsgCreateView, EsgUpdateView, EsgDeleteView, EsgDetailView
urlpatterns = [
path('search/', SearchResultsView.as_view(),name='search_results',),
path('', HomePageView.as_view(), name='home'),
path('createform/', EsgCreateView.as_view(), name='createform'),
path('update/<int:pk>', EsgUpdateView.as_view(), name='update'),
path('delete/<int:pk>', EsgDeleteView.as_view(), name='delete' ),
path('details/<int:pk>', EsgDetailView.as_view(), name='details'),
]
views.py
from .models import EsgDatabase
from django.urls import reverse_lazy
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.shortcuts import render
from django.views.generic import TemplateView, ListView, CreateView, UpdateView, DeleteView, DetailView
from django_tables2 import SingleTableView
from esgsheet.tables import EsgListViewTable
class EsgDetailView(DetailView):
template_name = 'details.html'
model = EsgDatabase
table_class = EsgListViewTable
context_object_name = 'esgdetail'
def get_success_url(self):
return reverse_lazy('details',kwargs={'pk':self.object.id})
class HomePageView(TemplateView):
template_name = 'home.html'
context_object_name = 'esghome'
#method_decorator(login_required, name='dispatch')
class EsgDeleteView(DeleteView):
template_name = 'delete.html'
model = EsgDatabase
table_class = EsgListViewTable
# success_url = reverse_lazy('home')
context_object_name = 'deleteview'
def get_success_url(self):
return reverse_lazy('home',kwargs={'pk':self.object.id})
#method_decorator(login_required, name='dispatch')
class EsgUpdateView(UpdateView):
model = EsgDatabase
fields = '__all__'
table_class = EsgListViewTable
template_name = 'update.html'
context_object_name = 'esgupdate'
strong textdef get_success_url(self):
return reverse_lazy('details', kwargs={'pk':self.object.id})
#method_decorator(login_required, name='dispatch')
class EsgCreateView(CreateView):
model = EsgDatabase
fields = '__all__'
template_name = 'forms.html'
def get_success_url(self):
return reverse_lazy('details', kwargs={'pk':self.object.id})
class SearchResultsView(SingleTableView):
model = EsgDatabase
table_class = EsgListViewTable
template_name = 'search_results.html'
SingleTableView.table_pagination = False
def get_queryset(self):
query = self.request.GET.get('q')
if query:
object_list = EsgDatabase.objects.filter(
Q(role__icontains=query) | Q(hq__icontains=query) |
Q(system__icontains=query) | Q(market__icontains=query) |Q(state__icontains=query) |
Q(zone__icontains=query) |Q(arrisseachangezone__icontains=query) |Q(xgsystem__icontains=query) |
Q(xgzonecode__icontains=query) | Q(syscode__icontains=query) |Q(fto__icontains=query) |
Q(xocnoc__icontains=query) |Q(snowticketassignment__icontains=query)
)
else:
object_list = self.model.objects.none()
return object_list
base.html
{% load django_tables2 %}
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
<center>
{% block title %}
{% endblock title %}
</center>
</head>
<body>
<!-- {% url 'home' as home %}
{% if request.path != home %}
<center> <br>
<form action="{% url 'search_results' %}" method="GET">
<input name='q' type="text" placeholder="Search ESG Database">
</form> <br>
</center>
{% endif %} -->
{% block content %}
{% endblock content %}
</body>
</html>
home.html
{% extends 'base.html' %}
{% block title %}
<h1>ESG Database</h1>
{% endblock title %}
{% block content %}
<center>
<form action="{% url 'search_results' %}" method="GET">
<input name='q' type="text" placeholder="Search ESG Database">
</form>
</center>
{% endblock content %}
delete.html
{% block title %}
{% endblock title %}
{% block content %}
<form method="POST">{% csrf_token %}
</form>
{% if user.is_authenticated %}
<a type="submit" class="btn btn-danger btn-sm" href="{% url 'delete' record.id %}" >Delete.html</a>
{% endif %}
{% endblock content %}
update.html
{% extends 'base.html' %}
{% block title %}
{% endblock title %}
{% block content %}
<form method="POST">
{% csrf_token %}
{{form.as_p}}
{% if user.is_authenticated %}
<a type="submit" class="btn btn-info btn-sm" href="{% url 'update' record.id %}" >Update.html</a>
{% endif %}
</form>
{% endblock content %}
search_results.html
{% extends 'base.html' %}
{% load render_table from django_tables2 %}
{% block title %}
<h1>ESG Database Results</h1>
{% endblock title %}
{% block content %}
{% render_table table %}
{% endblock content %}
forms.html
{% extends 'base.html' %}
{% block title %}
<h1>Create ESG Entry</h1>
{% endblock title %}
{% block content %}
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{form.as_p}}
{% if user.is_authenticated %}
<input type="submit" value="Submit">
{% endif %}
</form>
{% endblock content %}
details.html
{% extends 'base.html' %}
{% block title %}
<h1>Updated Detail View</h1>
{% endblock title %}
{% block content %}
<table class="table table-hover">
<thead>
<th>Role</th>
<th>HQ</th>
<th>System</th>
<th>Market</th>
<th>State</th>
<th>Zone</th>
<th>Arris/SeaChange Zone</th>
<th>xG System</th>
<th>xG Zone Code</th>
<th>Syscode</th>
<th>FTO</th>
<th>XOC/NOC</th>
<th>SNOW Ticket Assignment</th>
</thead>
<tbody>
<tr>
<td>{{esgdetail.role}}</td>
<td>{{esgdetail.hq}} </td>
<td>{{esgdetail.system}} </td>
<td>{{esgdetail.market}} </td>
<td>{{esgdetail.state}} </td>
<td>{{esgdetail.zone}} </td>
<td>{{esgdetail.arrisseachangezone}} </td>
<td>{{esgdetail.xgsystem}} </td>
<td>{{esgdetail.xgzonecode}} </td>
<td> {{esgdetail.syscode}} </td>
<td> {{esgdetail.fto}} </td>
<td>{{esgdetail.xocnoc}} </td>
<td> {{esgdetail.snowticketassignment}} </td>
<!-- <td>
edit
delete
</td> -->
</tr>
</tbody>
</table>
{% endblock content %}
Thanks to #funkybob at #django irc room. First I had to delete comments from my code because it was being parsed throwing NoReverseMatch errors. Second, I had to remove context_object_name from update and delete views.

Unable to Fetch particular product for each category

I am always getting all the food items in all Categories.
I want to display each Category with each food item.
Need to display Category with item belonging to that Category.
Please someone help me on this issue to resolve. I have tried looking over internet but couldn't find the solution to it
models.py
class Category(models.Model):
category_name = models.CharField(max_length=50)
def __str__(self):
return self.category_name
class Menu(models.Model):
dish_name = models.CharField(max_length=200, verbose_name='Name of Dish')
Desc = models.TextField(verbose_name='Dish Description')
Amount = models.IntegerField(null=False, blank=False, verbose_name='Amount of Dish')
date_posted = models.DateTimeField(default=timezone.now, verbose_name='Dish Date Posted')
category = models.ForeignKey(Category, on_delete=models.CASCADE, default=1)
def __str__(self):
return self.dish_name
views.py
def menu(request):
products = Menu.objects.all()
categories = Category.objects.all()
data = {}
data['products'] = products
data['categories'] = categories
template = 'food/menu.html'
return render(request, template, data)
html
{% for category in categories %}
{% if categories %}
<div class="col-xs-12 col-sm-6">
<div class="menu-section">
<h2 class="menu-section-title">{{ category.category_name }}</h2>
<hr>
{% endif %}
{% for i in products %}
<div class="menu-item">
<div class="menu-item-name">{{ i.dish_name}}</div>
<div class="menu-item-price">Rs {{ i.Amount}}</div>
<div class="menu-item-description">{{ i.Desc}}</div>
</div>
{% endfor %}
</div>
</div>
{% endfor %}
you are not filtering products based on categoris.
I would suggest doing something like this with data:
data = {
'categories': {
category: Menu.objects.filter(category=category) for category in categories
}
}
and in html you can:
{% for category, products in categories.items %}
{% if products %}
<div class="col-xs-12 col-sm-6">
<div class="menu-section">
<h2 class="menu-section-title">{{ category.category_name }}</h2>
<hr>
{% for i in products %}
<div class="menu-item">
<div class="menu-item-name">{{ i.dish_name}}</div>
<div class="menu-item-price">Rs {{ i.Amount}}</div>
<div class="menu-item-description">{{ i.Desc}}</div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
{% endfor %}

Reverse for 'viewpost' with arguments '(1,)' not found. 1 pattern(s) tried: ['int:post\\.id$']. Why am I getting this error?

I am trying to learn django and while making a viewport view, I came up with this error saying Reverse for 'viewpost' with arguments '(1,)' not found. 1 pattern(s) tried: ['int:post\\.id$'] I don't understand what is the mistake I am doing
Views.py
from django.shortcuts import render
from .models import Post
# Create your views here.
def main(request):
return render(request, "blog/index.html", {"Posts":Post.objects.all()})
def viewpost(request):
return render(request, "blog/viewpost.html")
urls.py
from django.urls import path, include
from . import views
urlpatterns = [
path('',views.main, name = 'main'),
path('viewpost/int:pk/', views.viewpost, name = 'viewpost')
]
index.html
{% extends 'blog/layout.html' %}
{% block body %}
<h1>Physics Blog</h1>
{% for post in Posts %}
<fieldset>
<h2>{{ post.Title }}</h2>
<h4>{{ post.Description }}</h4>
<h6>{{ post.Author }}</h6>
</fieldset>
<br>
{% endfor %}
{% endblock %}
viewpost.html
{% extends 'blog/layout.html' %}
{% block body %}
<h1>{{ post.Title }}</h1>
<h1>{{ post.Description }}</h1>
<h1>{{ post.Author }}</h1>
{% endblock %}
The problem is this line:
path('viewpost/int:pk/', views.viewpost, name = 'viewpost')
int:pk is missing the angular brackets. Change it to
path('viewpost/<int:pk>/', views.viewpost, name='viewpost')
The path() in your question doesn't seem to match 'int:post\\.id$ in the error message. So make sure you have saved the file and restarted runserver.
You'll also have to change viewpost so that it accepts the pk.
def viewpost(request, pk):

I want to represent DetailView and ListView in one Template. What can I do?

I want to express the detailview as the picture. I want to code the box part in the template of the picture.
enter image description here
It is as follows now.
views.py
#login_required
def product_detail(request, id, product_slug=None):
product = get_object_or_404(Product, id=id, slug=product_slug)
return render(request, 'shop/detail.html', {'product': product})
I think it should be modified to class. I would like to explain it by representing DetailView and ListView together in detail_template. I modified only views.py as shown below.
class ProductDetailView(DetailView, ListView):
model = Product
template_name = 'shop/detail.html'
context_object_name = 'latest_question_list'
#login_required
def get_queryset(self, id, product_slug=None):
product = get_object_or_404(Product, id=id, slug=product_slug)
return render(self, 'shop/detail.html', {'product': product})
This error occurs. AttributeError: 'ProductDetailView' object has no attribute 'user'
urls.py
urlpatterns = [
.........
path('<int:id>/<product_slug>/', product_detail, name='product_detail'),
.........
]
detail.html
{% extends 'base.html' %}
{% block title %}Product Detail{% endblock %}
{% block content %}
<div class="col">
<div class="alert alert-info" role="alert">Detail</div>
<div class="container">
<div class="row">
<div class="col-4">
<img src="{{product.image.url}}" width="100%">
</div>
<div class="col">
<h1 class="display-6">{{product.cname}}</h1>
<p class="card-text">{{product.pname}}</p>
<h5><span class="badge badge-secondary">Description</span>{{product.description|linebreaks }}</h5>
{% if product.author.username == user.username %}
Update
Delete
{% endif %}
{% if product.author.username != user.username %}
Inquiry
{% endif %}
Continue shopping
</div>
</div>
</div>
<p></p>
<div class="col">
<div class="alert alert-info" role="alert">Products added by registrants</div>
<div class="container">
{% for product in products %}
<div class="row">
{% if product.user.username == user.username %}
<div class="col-4">
<img src="{{product.image.url}}" width="auto" height="250">
</div>
<div class="col">
<h1 class="display-6">{{product.pname}}</h1>
<h5><span class="badge badge-secondary">Description</span>{{product.description|linebreaks}}</h5>
</div>
{% endif %}
</div>
{% endfor %}
</div>
{% endblock %}
Please help me how to fix it. I would also appreciate it if you would recommend any textbooks that I can refer to.
I have a similar situation. I wanted to display create form, detail and list on the same page:
urls:
example_urlpatterns = [
path('', views.ExampleCreateView.as_view(), name='_list'),
path('new/', views.ExampleCreateView.as_view(), name='_create'),
path('<int:pk>/', views.ExampleCreateView.as_view(), name='_detail'),
path('<int:pk>/del', views.ExampleDeleteView.as_view(), name='_del'),
]
urlpatterns = [
# ...
path('example/', include(example_urlpatterns)),
# ...
]
As you can see, I have two views, ExampleCreateView (also providing detail and list) and ExampleDeleteView for deleting. ExampleCreateView is primarily a create view:
class ExampleCreateView(CreateView):
template_name = 'example.html'
form_class = ExampleCreateForm
model = Example
def form_valid(self, form):
pass # Stuff to do with a valid form
# add user info from request to the form
def get_form_kwargs(self, *args, **kwargs):
kwargs = super().get_form_kwargs(*args, **kwargs)
kwargs['user'] = self.request.user
return kwargs
# Create appropriate context
def get_context_data(self, **kwargs):
kwargs['object_list'] = Example.objects.order_by('ip') # list
try: # If we have pk, create object with that pk
pk = self.kwargs['pk']
instances = Example.objects.filter(pk=pk)
if instances:
kwargs['object'] = instances[0]
except Exception as e:
pass # No pk, so no detail
return super().get_context_data(**kwargs)
Because I'm inheriting from CreateView, all the form processing is taken care of by default.
Adding the line kwargs['object_list'] =... makes it work as a list view, and the try block after that line makes it work as a detail view.
In the template all relevant parts are displayed:
{% if object %}
{% comment %}
...display the object... (Detail section)
{% endcomment %}
{% endif %}
{% if form %}
{% comment %}
...display the form... (Create section)
{% endcomment %}
{% endif %}
{% if object_list %}
{% comment %}
...display the list... (List section)
{% endcomment %}
{% endif %}
Let me know if this helps
Currently I have applied like this
views.py : modified
#method_decorator(login_required, name="dispatch")
class ProductDetailView(DetailView):
model = Product
template_name = 'shop/detail.html'
def get_context_data(self, **kwargs):
context = super(ProductDetailView, self).get_context_data(**kwargs)
context['product_list'] = Product.objects.all()
return context
index = ProductDetailView.as_view()
detail.html : modified
<div class="col">
<div class="alert alert-info" role="alert">Products added by this registrant</div>
<div class="container">
{% for prdt in product_list %}
{% if product.author.username == prdt.author.username %}
{% if product.pname != prdt.pname %}
{{ prdt }}<br>
{% endif %}
{% endif %}
{% endfor %}
</div>
enter image description here

Resources