Django reverse match error for keyword arguments - django
I am a newbie in python and I' training to make an app in Django to keep track of my clients problems in a personal training center.
I'm stuck in resolving a reverse match error for keyword arguments that is not passed. Honestly I am trying to understand how django manage this keyword arguments with no success.
The error that django throws me is:
NoReverseMatch at /persone/1/post
Reverse for 'cliente_detail' with keyword arguments '{'pk': ''}' not found. 1 pattern(s) tried: ['persone\\/(?P<pk>[0-9]+)\\/$']
Request Method: GET
Request URL: http://localhost:8000/persone/1/post
Django Version: 2.0.7
Exception Type: NoReverseMatch
Exception Value:
Reverse for 'cliente_detail' with keyword arguments '{'pk': ''}' not found. 1 pattern(s) tried: ['persone\\/(?P<pk>[0-9]+)\\/$']
Exception Location: C:\Users\perso\Envs\djangodev\lib\site-packages\django\urls\resolvers.py in _reverse_with_prefix, line 636
Python Executable: C:\Users\perso\Envs\djangodev\Scripts\python.exe
Python Version: 3.6.4
Python Path:
['C:\\Users\\perso\\Dropbox\\Django\\Frame\\filo_project',
'C:\\Users\\perso\\Envs\\djangodev\\Scripts\\python36.zip',
'C:\\Users\\perso\\Envs\\djangodev\\DLLs',
'C:\\Users\\perso\\Envs\\djangodev\\lib',
'C:\\Users\\perso\\Envs\\djangodev\\Scripts',
'c:\\users\\perso\\appdata\\local\\programs\\python\\python36-32\\Lib',
'c:\\users\\perso\\appdata\\local\\programs\\python\\python36-32\\DLLs',
'C:\\Users\\perso\\Envs\\djangodev',
'C:\\Users\\perso\\Envs\\djangodev\\lib\\site-packages']
Server time: Mar, 31 Lug 2018 11:58:32 +0200
My views.py:
import json
from django.http import HttpResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic.detail import DetailView
from django.views.generic.list import ListView
from django.views.generic.edit import UpdateView, CreateView, DeleteView, FormView
#Qui importo la classe per essere sicuro che se l'user non è loggato lo deve far loggare
from django.contrib.auth.decorators import login_required
#Ricordarsi di importare anche i modelli:
from .models import Cliente, FitCheck, Post
#login_required(login_url='/accounts/login/')
def home(request):
return render(request, "filogest/home.html")
class ClienteListView(LoginRequiredMixin, ListView):
#questa vista mi permette di visualizzare tutto l'elenco dei clienti
model = Cliente
template_name= "filogest/elenco_clienti.html"
#quetso per richiamare nel html il nome dell'elenco
context_object_name = 'elenco_clienti'
class ClienteDetailView(LoginRequiredMixin, DetailView):
model=Cliente
template_name="filogest/cliente_detail.html"
context_object_name = 'cliente_detail'
###############################
#Vai di editing di fitcheck
###############################
class FitcheckDetailView(LoginRequiredMixin, DetailView):
model=FitCheck
template_name="filogest/fitcheck_detail.html"
context_object_name = 'fitcheck_detail'
class FitcheckUpdateView(LoginRequiredMixin, UpdateView):
model = FitCheck
fields = ['idfitcheck','colazioneregolare']
template_name="filogest/fitcheck_update.html"
###############################
#Vai di editing di post
###############################
class PostDetailView(LoginRequiredMixin, DetailView):
model = Post
template_name="filogest/post_detail.html"
context_object_name = 'post_detail'
# def myPostListView(request, pk):
# idcli = get_object_or_404(Post, idclientepost=pk)
# posts_fisio = Post.objects.filter(tipologia="FI",idclientepost=idcli)
# posts_pale = Post.objects.filter(tipologia="PA",idclientepost=idcli)
# post = {"posts_fisio": posts_fisio, "posts_pale": posts_pale}
# return render(request, 'filogest/post_list.html', post)
class PostListView(LoginRequiredMixin, ListView):
model = Post
template_name = 'filogest/post_list.html'
context_object_name = 'post_list'
def get_context_data(self, *args, **kwargs):
context = super(PostListView, self).get_context_data(*args, **kwargs)
context['FisioPost'] = Post.objects.filter(tipologia="FI",idclientepost=self.kwargs['idclientepost'])
context['PalePost'] = Post.objects.filter(tipologia="PA",idclientepost=self.kwargs['idclientepost'])
context['fkPost'] = Post.objects.filter(idclientepost=self.kwargs['idclientepost'])
return context
class PostDetailCreate(LoginRequiredMixin, CreateView):
model = Post
template_name = 'post_create'
fields = '__all__'
###############################
#Vai di editing di post
###############################
#da controllare di brutto
def CercaPersona(request):
return render(request, "filogest/seleziona_cliente.html")
def AutocompleteCliente(request):
q = request.GET.get("term", "")
clienti = Cliente.objects.filter(nome__icontains=q)
results = []
for cliente in clienti:
place_json = {}
place_json = cliente.nome + " " + cliente.cognome
results.append(place_json)
data = json.dumps(results)
return HttpResponse(data, 'application/json')
models.py
from django.db import models
from django.contrib.auth.models import User
#importo timezone perchè così posso usare la funzione per capire quando è stato inserito
#un cliente oppure un fitcheck
from django.utils import timezone
from datetime import datetime
# Create your models here.
#questa funzione permette di far fare al sistema django i link per
#gli articoli referenziati
from django.urls import reverse
class Cliente(models.Model):
SESSO = (
('M','Maschio'),
('F','Femmina'),
)
idcliente = models.AutoField(primary_key=True)
nome = models.CharField(max_length=50)
cognome = models.CharField(max_length=50)
datadinascita = models.DateField()
sesso = models.CharField(max_length=1,choices=SESSO)
datainsert = models.DateTimeField(auto_now=True)
def __str__(self):
return self.cognome + " " + self.nome
def age(self):
return int((datetime.now().date() - self.datadinascita).days / 365.25)
#Qui uso questa funzione per far gestire al sistema i link che andro poi a richiamare
#con la classe.get_absolute_url
def get_absolute_url(self):
return reverse("filogest:cliente_detail", kwargs={"pk":self.idcliente})
class Meta:
# link utile : https://docs.djangoproject.com/en/2.0/ref/models/options/
verbose_name = "Cliente"
verbose_name_plural = "Clienti"
class FitCheck(models.Model):
STILE_PROFESSIONE = (
('PA','Poco attiva'),
('MA','Mediamente attiva'),
('A', 'Attiva'),
('MM','Molto Attiva'),
('US','Usurante'),
)
SI_NO = (
('S','Si'),
('N','No'),
)
ALIMENTAZIONE_TIPO = (
('D','Dietologo'),
('F', 'Fai da te'),
('N', 'Nutrizionista'),
('O', 'Nulla'),
)
STILE_DI_VITA = (
('PA','Poco Attivo'),
('MA', 'Mediamente Attivo'),
('AA', 'Attivo'),
('AM', 'Molto Attivo'),
('US', 'Usurante'),
)
OBIETTIVO_PRIMARIO = (
('DI','Dimagrimento'),
('PE', 'Performance'),
('DO', 'Dolore'),
('MU', 'Muscolazione'),
('FI', 'Fitness Generale'),
('GR', 'Gravidanza'),
('PG', 'Post Gravidanza'),
('PO', 'Postura'),
('RI', 'Rieducazione'),
('OP', 'Pre-Intervento'),
('CV', 'Cardio Vascolare'),
('PM', 'Prescrizione Medica'),
)
HA_DOLORE = (
('A','Acuto'), #dall'ultima settimana ha dolore
('S','Sub-acuto'), #dalla fase di dolore a 6 settimane
('C','Cronico'),
('N','No')
)
PROFESSIONE = (
('A','Altro'),
('C','Casalinga'),
('I','Impiegato'),
('O','Operaio'),
('S','Sportivo'),
('U','Studente'),
('P','Pensionato'),
('L','Libero Professionista'),
('T','Autista'),
)
STRESS = (
('PS','Poco Stressante'),
('ST','Stressante'),
('MS','Molto Stressante'),
)
DISP_ORARIA = (
('MA','Mattina'),
('PP','Pausa Pranzo'),
('PO','Pomeriggio'),
('SE','Sera'),
('TU','Turni'),
('LI','Libero'),
)
PROPOSTA_ACCETTATA = (
('S','Si'),
('N','No'),
('F','Fa Sapere'),
)
OSTEO = (
('F','Fatta'),
('D','Da Fare'),
('N','No'),
)
FONTE = (
('MA','Mattia'),
('PC','Paolo Cucchetti'),
('FD','Federico Dal Corso'),
('IN','Insegna'),
('IT','Internet'),
('UM','Monsellato'),
('MC','Marco'),
('PR','Paolo Roma'),
('TR','Trainer'),
('CL','Clienti'),
('MD','Medici'),
('AM','Amicizie'),
('VA','Varie'),
)
EFFETTUATO_DA = (
('MP','Marco P'),
('PR','Paolo R'),
('MA','Marco A'),
('PC','Paolo C'),
)
FUMATORE = (
('SI','Si'),
('ST','Saltuariamente'),
('NO','No'),
('EX','Ex'),
)
VAS = (
('0','0'),
('1','1'),
('2','2'),
('3','3'),
('4','4'),
('5','5'),
('6','6'),
('7','7'),
('8','8'),
('9','9'),
('10','10')
)
idfitcheck = models.OneToOneField(Cliente, on_delete=models.CASCADE, primary_key=True)
luogodinascita = models.CharField(max_length=50, verbose_name="Luogo di nascita")
email = models.EmailField(verbose_name="E-mail")
telefono = models.CharField(max_length=20, verbose_name="Numero di telefono")
indirizzo = models.CharField(max_length=100, verbose_name="Indirizzo")
citta = models.CharField(max_length=20, verbose_name="Città")
cap = models.CharField(max_length=5, verbose_name="CAP")
figli = models.CharField(max_length=50, verbose_name="Figli")
professione = models.CharField(max_length=1,choices=PROFESSIONE, verbose_name="Professione")
stileprofessione = models.CharField(max_length=2,choices=STILE_PROFESSIONE, verbose_name="Stile Professione")
stiledivita = models.CharField(max_length=2,choices=STILE_DI_VITA, verbose_name="Stile di vita")
stress = models.CharField(max_length=2,choices=STRESS, verbose_name="Come definisce il suo stile di vita?")
fumatore = models.CharField(max_length=2, choices=FUMATORE, verbose_name="Fuma?")
obiettivoprimario = models.CharField(max_length=2,choices=OBIETTIVO_PRIMARIO, verbose_name="Obiettivo Primario")
noteprimario = models.TextField(verbose_name="Note obiettivo primario")
obiettivosecondario = models.TextField(verbose_name="Obiettivo secondario")
alimentazione = models.CharField(max_length=2,choices=ALIMENTAZIONE_TIPO, verbose_name="Cura alimentazione")
alimcontrollataattiva = models.CharField(max_length=2,choices=SI_NO, verbose_name="Attualmente l'alimentazione è controllata")
pastialgiorno = models.IntegerField(verbose_name="Quanti pasti fa al giorno?")
colazioneregolare = models.CharField(max_length=2,choices=SI_NO, verbose_name="Fa colazione regolarmente?")
giabia = models.CharField(max_length=2,choices=SI_NO,verbose_name="Ha già fatto test BIA?")
attivitaattuali = models.CharField(max_length=2,choices=SI_NO,verbose_name="Attualmente svolge attività fisiche?")
attivitafisicarecente = models.CharField(max_length=500, verbose_name="Attività fisiche recenti")
attivitapassato = models.CharField(max_length=2,choices=SI_NO, verbose_name="In passato ha svolto attività?")
qualiattivita = models.CharField(max_length=500,verbose_name="Se si quali?")
assumealcool = models.CharField(max_length=2,verbose_name="Assume alcool?", choices=FUMATORE)
quantitaalcol = models.FloatField(verbose_name="Quanti bicchieri beve al giorno?")
attualmenteagonista = models.CharField(max_length=2,choices=SI_NO, verbose_name="Attualmente Agonista")
hadolore = models.CharField(max_length=2,choices=HA_DOLORE, verbose_name="Attualmente ha dolore?")
vasnrs = models.CharField(max_length=1, choices=VAS, verbose_name="Scala vas del dolore acuto e sub-acuto")
doloripassati = models.CharField(max_length=2,choices=SI_NO, verbose_name="Dolori in passato?")
notedoloripassati = models.TextField(verbose_name="Note su dolori")
traumipassati = models.CharField(max_length=2,choices=SI_NO, verbose_name="Ha subito traumi in passato")
interventichirurgici = models.CharField(max_length=2,choices=SI_NO)
notetraumiinterventi = models.TextField(verbose_name="Note traumi/interventi")
altremalattie = models.TextField(verbose_name="Altre malattie?")
altro = models.TextField(verbose_name="Altro da segnalare?")
disponibilitaoraria = models.CharField(max_length=2,choices=DISP_ORARIA)
freqsettimanale = models.FloatField(verbose_name="Quante volte riuscirebbe a venire regolarmente?")
seduteproposte = models.IntegerField(verbose_name="Sedute proposte dal trainer")
propostaaccettata = models.CharField(max_length=1,choices=PROPOSTA_ACCETTATA, verbose_name="Proposta fatta dal trainer accettata?")
fonte = models.CharField(max_length=2,choices=FONTE, verbose_name="Fonte")
sedutaprova = models.CharField(max_length=2,choices=SI_NO, verbose_name="Seduta di prova fissata?")
totaleeconomico = models.FloatField(verbose_name="Totale economico proposto?")
biaprogrammata = models.CharField(max_length=1,choices=OSTEO, verbose_name="Bia programmata?")
osteoprogrammata = models.CharField(max_length=1,choices=OSTEO, verbose_name="Valutazione osteopatica programmata?")
fisioprogrammata = models.CharField(max_length=1,choices=OSTEO, verbose_name="Valutazione fisioterapica programmata?")
stapedio = models.CharField(max_length=2,choices=SI_NO)
datainserimento= models.DateTimeField(auto_now=True)
effettuato = models.CharField(max_length=2, choices=EFFETTUATO_DA, verbose_name="Colloquio effettuato da?")
def __str__(self):
return self.idfitcheck.cognome + " "+ self.idfitcheck.nome
def nome_persona(self):
return self.idfitcheck.cognome + " "+ self.idfitcheck.nome
def fitchekpk(self):
return self.idfitcheck
def get_absolute_url(self):
return reverse("filogest:fitcheck_detail", kwargs={"pk":self.idfitcheck})
class Meta:
# link utile : https://docs.djangoproject.com/en/2.0/ref/models/options/
verbose_name = "FitCheck"
verbose_name_plural = "FitChecks"
#da qui parte lo script per il modello di balke che prendere:
#1- età
#2-SESSO
#3-Peso che va creato ad ok
#4- da qui calcolare poi la frequenza cardiaca massima
#5- permettere l'inserimento dei dati del test
#6- elaborare e salvare i risultati
class Balke(models.Model):
idbalke = models.ForeignKey(Cliente,on_delete=models.CASCADE, related_name="filogest_balke_clienti")
etasogg = models.IntegerField()
pesosogg = models.FloatField()
blocco1=models.IntegerField()
blocco2=models.IntegerField()
blocco3=models.IntegerField()
blocco4=models.IntegerField()
blocco5=models.IntegerField()
blocco6=models.IntegerField()
blocco7=models.IntegerField()
def __str__ (self):
return self.idbalke.cognome + " "+ self.idbalke.nome
def cooper(self):
return 220-Cliente.age
def tanaka(self):
return (208-(0,7*Cliente.age))
class Post(models.Model):
OBIETTIVO_PERSONA = (
('DI','Dimagrimento'),
('PE', 'Performance'),
('DO', 'Dolore'),
('MU', 'Muscolazione'),
('FI', 'Fitness Generale'),
('GR', 'Gravidanza'),
('PG', 'Post Gravidanza'),
('PO', 'Postura'),
('RI', 'Rieducazione'),
('OP', 'Pre-Intervento'),
('CV', 'Cardio Vascolare'),
('PM', 'Prescrizione Medica'),
)
TIPO = (
('FI', 'Fisio / Osteo'),
('PA', 'Palestra'),
)
idpost = models.AutoField(primary_key=True)
idclientepost = models.ForeignKey(Cliente, on_delete=models.CASCADE, related_name="cliente")
tipologia = models.CharField(max_length=2, choices=TIPO)
titolo = models.CharField(max_length=250)
obiettivo = models.CharField(max_length=2, choices=OBIETTIVO_PERSONA)
autore = models.ForeignKey(User, on_delete=models.CASCADE,related_name="filogest_post")
corpo = models.TextField()
creato = models.DateTimeField(auto_now=True)
class Meta:
ordering = ('-creato',)
def get_absolute_url(self):
return reverse("filogest:post_detail", kwargs={"idclientepost": self.idclientepost.idcliente, "pk":self.idpost})
return reverse("filogest:post_list", kwargs={"idclientepost": self.idclientepost.idcliente})
def __str__(self):
return self.titolo
Urls.py:
from django.urls import path, include, reverse
from .views import home, ClienteListView, ClienteDetailView, AutocompleteCliente, CercaPersona, FitcheckDetailView, FitcheckUpdateView
from .views import PostListView, PostDetailView, PostListView
app_name='filogest'
urlpatterns = [
path ('', home, name='homepage'),
path ('persone/', ClienteListView.as_view(), name='elenco_clienti'),
path ('persone/<int:pk>/', ClienteDetailView.as_view(), name='cliente_detail'),
path ('getperson/', AutocompleteCliente, name='autocomplete_cliente'),
path ('cercaper/', CercaPersona, name='cerca_persona'),
path ('persone/<int:pk>/fitcheck', FitcheckDetailView.as_view(), name='fitcheck_detail'),
path ('persone/<int:pk>/fitcheckupdate', FitcheckUpdateView.as_view(), name='fitcheck_update'),
#uso idcliente post perchè il modello è il post ma il riferimento è la chiave esterna
path ('persone/<int:idclientepost>/post', PostListView.as_view(), name='post_list'),
path ('persone/<int:idclientepost>/post/<int:pk>',PostDetailView.as_view(), name='post_detail'),
]
cliente_detail template
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block head_title %}{{ block.super }} - Dettagli Cliente{% endblock head_title %}
{% block content %}
<br>
<div class="">
<button type="button" class="btn btn-primary" onclick="location.href='{% url 'filogest:cliente_detail' pk=cliente_detail.idcliente %}';">Dettagli Anagrafici</button>
<button type="button" class="btn btn-primary" onclick="location.href='{% url 'filogest:fitcheck_detail' pk=cliente_detail.idcliente %}';">FitCheck</button>
<button type="button" class="btn btn-primary" onclick="location.href='{% url 'filogest:post_list' idclientepost=cliente_detail.idcliente %}';">Note operative</button>
<button type="button" class="btn btn-primary">Test Balke</button>
<button type="button" class="btn btn-primary">Test Motori</button>
</div>
<br>
<div class="alert alert-warning" role="alert">
<br>
<h1>Dettagli persona:</h1>
<hr>
<strong>Cognome:</strong> {{ cliente_detail.cognome }} <br>
<strong>Nome:</strong> {{ cliente_detail.nome }} <br>
<strong>Data di nascita:</strong> {{ cliente_detail.datadinascita }} <br>
<strong>Sesso:</strong> {{ cliente_detail.sesso }} <br>
<strong>Età:</strong> {{ cliente_detail.age }} <br>
<hr>
</div>
{% endblock content %}
post_list
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block head_title %}{{ block.super }} - Dettagli Cliente{% endblock head_title %}
{% block content %}
<br>
<div class="">
<button type="button" class="btn btn-primary" onclick="location.href='{% url 'filogest:cliente_detail' pk=post_list.idclientepost %}';">Dettagli Anagrafici</button>
<button type="button" class="btn btn-primary" onclick="location.href='{% url 'filogest:fitcheck_detail' pk=1 %}';">FitCheck</button>
<button type="button" class="btn btn-primary">Note operative</button>
<button type="button" class="btn btn-primary">Test Balke</button>
<button type="button" class="btn btn-primary">Test Motori</button>
</div>
<div>
<br>
<h1>Commenti di {% for post in fkPost %}
{% if forloop.first %}
{{ post.idclientepost.cognome }} {{ post.idclientepost.nome}}
{% endif %}
{% endfor %}</h1>
<div class="container">
<div class="row">
<div class="col">
<h2>Note Osteofisio :</h2>
<br>
{% for post in FisioPost %}
<div class="p-2 border border-primary">
<strong>Titolo:</strong> {{ post.titolo }} <br>
<strong>Obiettivo:</strong> {{post.get_obiettivo_display}} <br>
<div class="p-1 border">
<strong>Nota:</strong><br>
{{post.corpo}}<br>
</div>
<i>Creato da: <strong>{{post.autore}}</strong> in data {{post.creato}}</i>
{{post.idclientepost}}
</div>
{% endfor %}
</div>
<div class="col">
<h2>Note Trainer:</h2>
<br>
{% for post in PalePost %}
<div class="p-2 border border-success">
<strong>Titolo:</strong> {{ post.titolo }} <br>
<strong>Obiettivo:</strong> {{post.get_obiettivo_display}} <br>
<div class="p-1 border">
<strong>Nota:</strong><br>
{{post.corpo}}<br>
</div>
<i>Creato da: <strong>{{post.autore}}</strong> in data {{post.creato}}</i>
</div>
{% endfor %}
</div>
</div>
</div>
{% endblock content %}
Any help would be appreciated.
As far as I can see this exception is raised at PostListView. In your template filogest/post_list.html you have a detail button:
<button type="button" class="btn btn-primary" onclick="location.href='{% url 'filogest:cliente_detail' pk=post_list.idclientepost %}';">Dettagli Anagrafici</button>
You are creating the url with the argument pk=post_list.idclientepost. I believe the post_list.idclientepost maybe null or blank for the instance. As it's mentioned in the error pk is passed blank (with keyword arguments '{'pk': ''}').
Reverse for 'cliente_detail' with keyword arguments '{'pk': ''}' not found. 1 pattern(s) tried: ['persone\\/(?P<pk>[0-9]+)\\/$']
Related
Add products with different sizes and price to Cart | Django
I use session's to create a shopping cart. I have a product model and a model for Product-sizes, which I define the size-title(XL , etc) and price of product in it . So that I can have products with different sizes as well as different prices. But my logic has some problems if I add product_1 with size A , it's ok ... if I add product_1 with size B , it's ok ... but when I'm trying to add same product with different sizes at same time the cart only shows the price of first size #shop/models.py class ProductSizes(models.Model): name = models.CharField(max_length=50) price = models.IntegerField() picture = models.ImageField(upload_to="products/%Y/%m/%d" ) class Product(models.Model): name = models.CharField(max_length=100) size = models.ManyToManyField(ProductSizes , blank=True , related_name="sizes" ) price = models.IntegerField() #cart/cart.py from django.conf import settings from shop.models import Product class Cart: def __init__(self,request): self.session = request.session cart = self.session.get(settings.CART_SESSION_ID) if not cart: cart = self.session[settings.CART_SESSION_ID] = {} self.cart = cart # add to cart def add(self,product,size_,quantity=1,override_quantity=False): product_id = str(product.id) print(product.size.name) if product_id not in self.cart : if size_ != None: if size_.off_price: self.cart[product_id] = {'quantity':0,'price':size_.off_price} elif size_.price: self.cart[product_id] = {'quantity':0,'price':size_.price} else: if product.off_price: self.cart[product_id] = {'quantity':0,'price':product.off_price} else: self.cart[product_id] = {'quantity':0,'price':product.price} if override_quantity: self.cart[product_id]['quantity'] = quantity else: self.cart[product_id]['quantity'] += quantity self.save() def save(self): self.session.modified = True #remove from cart def remove(self,product): product_id = str(product.id) if product_id in self.cart: del self.cart[product_id] self.save() def __iter__(self): product_ids = self.cart.keys() products = Product.objects.filter(id__in=product_ids) cart = self.cart.copy() for product in products: cart[str(product.id)]['product'] = product for item in cart.values(): item['total_price'] = item['price'] * item['quantity'] yield item def __len__(self): return sum(item['quantity'] for item in self.cart.values()) def get_total_price(self): return sum(item['price'] * item['quantity'] for item in self.cart.values()) def clear(self): del self.session[settings.CART_SESSION_ID] self.save() ــــــــــــــــــ from django.shortcuts import get_object_or_404 , redirect , render from django.views.decorators.http import require_POST from .cart import Cart from shop.models import Product, ProductSizes from .forms import CartAddProductForm #require_POST def cart_add(request , product_id , size): cart = Cart(request) product = Product.objects.get(id=product_id) if size != 0: size_ = product.size.get(id=size) else: size_ = None form = CartAddProductForm(request.POST) if form.is_valid(): cd = form.cleaned_data cart.add(product=product , quantity=cd['quantity'] ,size_=size_, override_quantity=cd['override'] ) return redirect("home") #require_POST def cart_remove(request , product_id): cart = Cart(request) product = get_object_or_404(Product,id=product_id) cart.remove(product=product) return redirect("cart.detail") def cart_detail(request): cart = Cart(request) for item in cart: item['update_quantity_form'] = CartAddProductForm(initial={ 'quantity':item["quantity"], "override":True, }) return render(request , "cart.html" , {"cart":cart}) #cart/forms.py & urls from django import forms PRODUCT_QUANTITY_CHOICES = [(i , str(i)) for i in range(1,21)] class CartAddProductForm(forms.Form): quantity = forms.TypedChoiceField(choices=PRODUCT_QUANTITY_CHOICES,coerce=int) override = forms.BooleanField(required=False, initial=False,widget=forms.HiddenInput) --------------- urlpatterns = [ path("" , views.cart_detail , name="cart.detail"), path("add/<int:product_id>/<int:size>/" , views.cart_add , name="cart.add"), path("remove/<int:product_id>/" , views.cart_remove , name="cart.remove"), ] #html <div class="shopping-cart-wrap"> <span class="cart-total-amunt">{{cart.get_total_price}} تومان</span><i class="icon-shopping-bag2 float-left"></i><span class="cart-total">{{cart|length}}</span> <ul class="mini-cart"> {% for item in cart %} <li class="cart-item"> <div class="cart-image"> <img alt="" src="/media/{{item.product.picture}}" width="80" height="80"> </div> <div class="cart-title"> <a href="single-product.html"> <h4>{{item.product.name}}</h4> </a> <div class="quanti-price-wrap"> <span class="quantity">{{item.quantity}} ×</span> <div class="price-box"><span class="new-price">{{item.price}} تومان</span></div> </div> <a class="{% url 'cart.remove' item.product.id %}" href="#"><i class="icon-x"></i></a> </div> </li> {% endfor %} <li class="subtotal-box"> <div class="subtotal-title"> <h3>جمع کل :</h3><span>{{cart.get_total_price}} تومان</span> </div> </li> <li class="mini-cart-btns"> <div class="cart-btns"> مشاهده سبد پرداخت </div> </li> </ul> </div>
after 2 days of struggling finally I found the solution for adding products with different sizes you have to pass the size model id to session instead of the product id shop/models.py class ProductSizes(models.Model): name = models.CharField(max_length=50) price = models.IntegerField() off_price = models.IntegerField(blank=True , null=True) picture = models.ImageField(upload_to="products/%Y/%m/%d" ) product = models.ForeignKey("Product" , on_delete=models.CASCADE ) class Product(models.Model): name = models.CharField(max_length=100) description = models.TextField(blank=True) picture = models.ImageField(upload_to="products/%Y/%m/%d" ) picture2 = models.ImageField(upload_to="products/%Y/%m/%d" , blank=True) picture3 = models.ImageField(upload_to="products/%Y/%m/%d" , blank=True) picture4 = models.ImageField(upload_to="products/%Y/%m/%d" , blank=True) price = models.IntegerField() available = models.BooleanField(default=True) category = models.ForeignKey(Category ,on_delete=models.CASCADE , blank=True ,null=True ) slug = models.SlugField(max_length=100 , db_index=True , unique=True) tags = TaggableManager(blank=True) is_amazing = models.BooleanField(default=False) amazing_till = models.CharField(max_length=10 , null=True , blank=True) off_price = models.IntegerField(blank=True , null=True) brand = models.ForeignKey(Brand ,on_delete=models.CASCADE , blank=True ,null=True ) created_at = models.DateField(auto_now_add=True) update_at = models.DateField(auto_now=True) def get_absolute_url(self): return reverse('get.single.product', kwargs={'slug': self.slug}) class Meta: ordering=("name",) index_together = (('id' , 'slug'),) cart/cart.py from django.conf import settings from shop.models import Product, ProductSizes class Cart: def __init__(self,request): self.session = request.session cart = self.session.get(settings.CART_SESSION_ID) if not cart: cart = self.session[settings.CART_SESSION_ID] = {} self.cart = cart # add to cart def add(self,product,size_,quantity=1,override_quantity=False): size_id = str(size_.id) if size_id not in self.cart: if size_.price: self.cart[size_id] = {'quantity': 0, 'price': size_.price} elif size_.off_price: self.cart[size_id] = {'quantity': 0, 'price': size_.off_price} self.cart[size_id]['quantity'] += quantity self.save() self.save() def save(self): self.session.modified = True #remove from cart def remove(self,size_): product_id = str(size_.id) if product_id in self.cart: del self.cart[product_id] self.save() def __iter__(self): sizes_ids = self.cart.keys() products = ProductSizes.objects.filter(id__in=sizes_ids) cart = self.cart.copy() for size in products: cart[str(size.id)]['size'] = size for item in cart.values(): item['total_price'] = item['price'] * item['quantity'] yield item def __len__(self): return sum(item['quantity'] for item in self.cart.values()) def get_total_price(self): return sum(item['price'] * item['quantity'] for item in self.cart.values()) def clear(self): del self.session[settings.CART_SESSION_ID] self.save() cart/views.py #require_POST def cart_add(request , product_id , size): cart = Cart(request) product = Product.objects.get(id=product_id) size_ = get_object_or_404(ProductSizes , id=size) form = CartAddProductForm(request.POST) if form.is_valid(): cd = form.cleaned_data cart.add(product=product , quantity=cd['quantity'] ,size_=size_, override_quantity=cd['override'] ) return redirect("home") The template {% block cart %} <div class="shopping-cart-wrap"> <span class="cart-total-amunt">{{cart.get_total_price}} تومان</span><i class="icon-shopping-bag2 float-left"></i><span class="cart-total">{{cart|length}}</span> <ul class="mini-cart"> {% for item in cart %} <li class="cart-item"> <div class="cart-image"> <img alt="" src="/media/{{item.size.product.picture}}" width="80" height="80"> </div> <div class="cart-title"> <a href="single-product.html"> <h4>{{item.size.name}}</h4> </a> <div class="quanti-price-wrap"> <span class="quantity">{{item.quantity}} ×</span> <div class="price-box"><span class="new-price">{{item.price}} تومان</span></div> </div> <a class="{% url 'cart.remove' item.size.id %}" href="#"><i class="icon-x"></i></a> </div> </li> {% endfor %} <li class="subtotal-box"> <div class="subtotal-title"> <h3>جمع کل :</h3><span>{{cart.get_total_price}} تومان</span> </div> </li> <li class="mini-cart-btns"> <div class="cart-btns"> مشاهده سبد پرداخت </div> </li> </ul> </div> {% endblock cart %}
formset function update view does not save the forms because the id is missing
I have a view to update 6 of my formset only that the click of the send button gives me the error that the id of each form is missing ... how do you fix it? When I have to create formset there are never problems with the id... Can anyone tell me where I'm wrong? I leave my code below view #login_required def PianoSingleUpdateView(request, id): piano = models.Piano.objects.get(single_piano__id = id) piano_sett = models.PianoSingleDay.objects.get(id = id) dato = models.PianoDay.objects.filter( piano_day = piano_sett) DatiFormSet = modelformset_factory(models.PianoDay, extra = 0, fields=('id', 'kcal', 'carboidrati', 'proteine', 'grassi')) if request.method == 'POST': dati_formset = DatiFormSet(request.POST, request.FILES, queryset = dato) if dati_formset.is_valid(): for dato in dati_formset: dato.save() return redirect('gestione-piano', id = piano.id) else: dati_formset = DatiFormSet(queryset = dato) context = {'piano': piano, 'piano_sett': piano_sett, 'dati_formset': dati_formset} return render(request, 'crud/update/update_piano_giornaliero.html', context) models class Piano(models.Model): nome_piano = models.CharField(max_length=100) data_inizio = models.DateField() data_fine = models.DateField() utente_piano = models.ForeignKey( User, on_delete = models.CASCADE, related_name = 'utente_piano' ) def __str__(self): return self.nome_piano class PianoSingleDay(models.Model): giorni_settimana_scelta = [ ("1","Lunedì"), ("2","Martedì"), ("3","Mercoledì"), ("4","Giovedì"), ("5","Venerdì"), ("6","Sabato"), ("7","Domenica") ] giorni_settimana = models.CharField( choices = giorni_settimana_scelta, max_length = 300 ) single_piano = models.ForeignKey( Piano, on_delete = models.CASCADE, related_name = 'single_piano' ) def __str__(self): return self.giorni_settimana class PianoDay(models.Model): scelta_pasto = [ ("1","Colazione"), ("2","Spuntino mattina"), ("3","Pranzo"), ("4","Merenda"), ("5","Cena"), ("6","Spuntino sera") ] pasto = models.CharField( choices = scelta_pasto, max_length = 300, default = '-' ) kcal = models.IntegerField(default = 0) grassi = models.IntegerField(default = 0) carboidrati = models.IntegerField(default = 0) proteine = models.IntegerField(default = 0) piano_day = models.ForeignKey( PianoSingleDay, on_delete = models.CASCADE, related_name = 'piano_day' ) file html <form method="post" novalidate autocomplete="off" class="form-not-box"> {% csrf_token %} <div class="box-schede"> <div class="alert alert-pop-up mt-3" role="alert"> Le colonne lasciate a 0 non verranno considerate. </div> {{ dati_formset.management_form }} <div class="row mt-3"> {% for dati in dati_formset %} <div class="col-lg-2"> <div class="info-piano"> <div class="ico"> {% if forloop.counter == 1 %} <object type="image/svg+xml" data="{% static 'img/icone/colazione.svg' %}"> Icona colazione </object> {% elif forloop.counter == 3 %} <object type="image/svg+xml" data="{% static 'img/icone/pranzo.svg' %}"> Icona pranzo </object> {% elif forloop.counter == 5 %} <object type="image/svg+xml" data="{% static 'img/icone/cena.svg' %}"> Icona cena </object> {% elif forloop.counter == 2 or forloop.counter == 4 or forloop.counter == 6 %} <object type="image/svg+xml" data="{% static 'img/icone/merenda.svg' %}"> Icona cena </object> {% endif %} </div> <div class="form-floating mb-3 mt-3"> {{ dati.kcal|add_class:'form-control'|append_attr:"placeholder: dati" }} {{ dati.kcal.label_tag }} </div> <div class="form-floating mb-3"> {{ dati.carboidrati|add_class:'form-control'|append_attr:"placeholder: dati" }} {{ dati.carboidrati.label_tag }} </div> <div class="form-floating mb-3"> {{ dati.proteine|add_class:'form-control'|append_attr:"placeholder: dati" }} {{ dati.proteine.label_tag }} </div> <div class="form-floating"> {{ dati.grassi|add_class:'form-control'|append_attr:"placeholder: dati" }} {{ dati.grassi.label_tag }} </div> </div> </div> {% endfor %} </div> </div> <div class="buttons mb-3"> Indietro <input type="submit" class="btn btn-warning" value="Aggiorna piano"> </div> </form>
My observation tells me that your problem is the DatiFormSet fields which shouldn't contain id value and also your function view had in queryset = dato which is not needed, but in some cases you should add an instance of Piano. #login_required def PianoSingleUpdateView(request, id): piano = models.Piano.objects.get(single_piano__id = id) piano_sett = models.PianoSingleDay.objects.get(id = id) dato = models.PianoDay.objects.filter( piano_day = piano_sett) DatiFormSet = modelformset_factory(models.PianoDay, extra = 0, fields=('kcal', 'carboidrati', 'proteine', 'grassi')) if request.method == 'POST': dati_formset = DatiFormSet(request.POST, request.FILES , instance=piano) if dati_formset.is_valid(): for dato in dati_formset: dato.save() return redirect('gestione-piano', id = piano.id) else: dati_formset = DatiFormSet(request.POST) context = {'piano': piano, 'piano_sett': piano_sett, 'dati_formset': dati_formset} return render(request, 'crud/update/update_piano_giornaliero.html', context)
How to display your queries using filter?
So I am trying to set up a filter for my website and it is not working; It does not give me an error and the url updates like a query is being made but when I click "submit" it still shows all of the content in the page. I can't quite figure out what is wrong. filters.py import django_filters from django_filters import DateFilter from .models import * class UserpostFilter(django_filters.FilterSet): start_date = DateFilter(field_name = "date_published", lookup_expr='gte') end_date = DateFilter(field_name = "date_published", lookup_expr='lte') class Meta: model = Userpost fields = '__all__' exclude = ['image', 'user', 'date_published'] models.py class Userpost(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True) Year = models.CharField(max_length = 4) Mileage = models.CharField(max_length = 8) Make = models.CharField(max_length = 50) Model = models.CharField(max_length = 50) Price = models.DecimalField(max_digits=15, decimal_places=2) email = models.EmailField() date_published = models.DateField(default = timezone.now) image = models.ImageField(null = True, blank = True, upload_to = r"C:\Users\gabri\Desktop\test\ecommerce\static\images") def __str__(self): return self.Year + " " + self.Make + " " + self.Model #property def imageURL(self): try: url = self.image.url except: url = '' return url views.py def posts(request): cars = Userpost.objects.all() p = Paginator(Userpost.objects.all(), 9) page = request.GET.get('page') cars_list = p.get_page(page) nums = "a" * cars_list.paginator.num_pages myFilter = UserpostFilter(request.GET, queryset = cars) cars = myFilter.qs context = {'cars':cars, 'cars_list':cars_list, "nums":nums, "myFilter":myFilter} return render(request, 'store/userposts.html', context) userposts.html <div class = "row"> <div class="col"> <div class = "card card-body"> <form method="get"> {{myFilter.form}} <button class="btn btn-primary" type="submit">Search</button> </form> </div> </div> </div> <br> <div class="row"> {% for car in cars_list %} <div class="col-lg-4"> <img class="thumbnail" src="{{car.imageURL|default:'/images/transparentLogo.png'}}"> <div class="box-element product"> <h6><strong>{{car.Year}} {{car.Make}} {{car.Model}}</strong></h6> <hr> <a class="btn btn-outline-success" href="{% url 'post_detail' car.pk %}">View</a> <h4 style="display: inline-block; float: right"><strong>${{car.Price|floatformat:2}}</strong></h4> </div> </div> {% endfor %} </div> I would really appreciate if you guys could help me EDIT So I changed the order of the views to first filter and then paginate but it still does the same thing. I get no error, but display all the content from the page rather than the filtered ones. def posts(request): cars = Userpost.objects.all() myFilter = UserpostFilter(request.GET, queryset=cars) cars = myFilter.qs p = Paginator(Userpost.objects.all(), 9) page = request.GET.get('page') cars_list = p.get_page(page) nums = "a" * cars_list.paginator.num_pages context = {'cars':cars, "myFilter":myFilter, 'cars_list':cars_list, "nums":nums} return render(request, 'store/userposts.html', context)
The paginator should work on the cars not on the orignal queryset, since you are paginate over the filtered results def posts(request): cars = Userpost.objects.all() myFilter = UserpostFilter(request.GET, queryset=cars) if not myFilter.is_valid(): raise ValidationError('filter is invalid') cars = myFilter.qs # This is the change p = Paginator(cars, 9) page = request.GET.get('page') cars_list = p.get_page(page) nums = "a" * cars_list.paginator.num_pages context = {'cars':cars, "myFilter":myFilter, 'cars_list':cars_list, "nums":nums} return render(request, 'store/userposts.html', context)
Django nested forms
I have trouble figuring out how to create nested forms. I have two models: Poll and Question (foreign key for Poll is inside Question model). I want it to be possible to add several questions for the poll dynamically inside one form. I've already tried making it work with inlineform_factory, but found troubles saving the form. Right now I have overcomplicated code that throws MultiValueDictError after saving the poll for the second time. I thought maybe there is some other way. Here's my code models.py class Question(models.Model): type_choices = ( ('text', 'Текстовый'), ('integer', 'Числовой'), ) type = models.CharField(verbose_name=u'Тип вопроса', choices=type_choices, max_length=70) text = models.CharField(verbose_name=u'Текст вопроса', max_length=255) poll = models.ForeignKey('Poll', on_delete=models.CASCADE, related_name='questions') class Poll(BaseFields): objects = models.Manager() published = PublishedManager() title = models.CharField(verbose_name=u'Заголовок', max_length=70) date_from = models.DateTimeField(u'Дата начала') date_to = models.DateTimeField(u'Дата окончания') status = models.IntegerField(choices=Status.choices, default=0) def status_name(self): return dict(Status.choices).get(self.status) def update_url(self): return reverse('poll_update', args=(self.id, )) forms.py QuestionInlineFormSet = inlineformset_factory(Poll, Question, extra=1, can_delete=False, fields=('type', 'text', 'poll'), widgets={ 'type': w.Select(attrs={'class': 'form-control'}), 'text': w.TextInput(attrs={'class': 'form-control'}), }) class PollForm(CommonForm): class Meta(CommonForm.Meta): model = Poll views.py class Create(BaseCreateView): template_name = 'back/poll/poll.html' page_title = 'Создание опроса' model = Poll form_class = PollForm def form_valid(self, form): result = super(Create, self).form_valid(form) questions_formset = QuestionInlineFormSet(data=form.data, instance=self.object, prefix='questions_formset') if questions_formset.is_valid(): questions_formset.save() return result def get_context_data(self, **kwargs): context = super(Create, self).get_context_data(**kwargs) context['questions_formset'] = QuestionInlineFormSet(prefix='questions_formset') return context class Update(BaseUpdateView): template_name = 'back/poll/poll.html' page_title = 'Редактирование опроса' model = Poll form_class = PollForm def form_valid(self, form): result = super(Update, self).form_valid(form) questions_formset = QuestionInlineFormSet(data=form.data, instance=self.object, prefix='questions_formset') if questions_formset.is_valid(): questions_formset.save() return result def get_context_data(self, **kwargs): context = super(Update, self).get_context_data(**kwargs) context['questions_formset'] = QuestionInlineFormSet(instance=self.get_object(), prefix='questions_formset') return context poll.html {% extends 'back/base/form/base.html' %} {% block form %} {% include "back/includes/status_buttons.html" %} <div class="row"> <div class="col-md-7"> <div class="row" style="margin-bottom: 15px;"> <div class="col-md-12"> {% include 'back/includes/status_label.html' %} </div> </div> {% include "back/base/form/field.html" with field=form.title %} {% include "back/base/form/datetime_field.html" with field=form.date_from %} {% include "back/base/form/datetime_field.html" with field=form.date_to %} {{ questions_formset.management_form }} {% for question_form in questions_formset %} {% include "back/poll/question.html" with form=question_form %} {% endfor %} <div style="float: right; margin-right: 45px"> <button class="btn btn-success add-form-row">Добавить вопрос</button> </div> </div> </div> {% endblock %} question.html <div class="questions"> <div class="row form-row"> <div class="form-group col-md-5{% if form.type.errors %} has-error{% endif %}"> <label>{{ form.type.label }}</label> {{ form.type }} <p class="help-block">{{ form.type.errors }}</p> </div> <div class="form-group col-md-5{% if form.text.errors %} has-error{% endif %}"> <label>{{ form.text.label }}</label> {{ form.text }} <p class="help-block">{{ form.text.errors }}</p> </div> <div class="col-md-2" style="margin-top: 25px"> <button type="button" class="btn btn-danger remove-form-row">✕</button> </div> </div> </div> <script> function updateElementIndex(el, prefix, ndx) { let id_regex = new RegExp('(' + prefix + '-\\d+)'); let replacement = prefix + '-' + ndx; if ($(el).attr("for")) $(el).attr("for", $(el).attr("for").replace(id_regex, replacement)); if (el.id) el.id = el.id.replace(id_regex, replacement); if (el.name) el.name = el.name.replace(id_regex, replacement); } function deleteForm(prefix, btn) { let total = parseInt($('#id_' + prefix + '_formset' + '-TOTAL_FORMS').val()); if (total > 1) { btn.closest('.form-row').remove(); let forms = $('.form-row'); $('#id_' + prefix + '_formset' + '-TOTAL_FORMS').val(forms.length); for (let i = 0, formCount = forms.length; i < formCount; i++) { $(forms.get(i)).find(':input').each(function () { updateElementIndex(this, prefix, i); }); } } } function cloneMore(selector, prefix) { let newElement = $(selector).clone(true); let total = $('#id_' + prefix + '_formset' + '-TOTAL_FORMS').val(); newElement.find(':input:not([type=button]):not([type=submit]):not([type=reset])').each(function () { let name = $(this).attr('name').replace('-' + (total - 1) + '-', '-' + total + '-'); let id = 'id_' + name; $(this).attr({'name': name, 'id': id}).val('').removeAttr('checked'); }); newElement.find('label').each(function () { let forValue = $(this).attr('for'); if (forValue) { forValue = forValue.replace('-' + (total - 1) + '-', '-' + total + '-'); $(this).attr({'for': forValue}); } }); total++; $('#id_' + prefix + '_formset' + '-TOTAL_FORMS').val(total); $(selector).after(newElement); } $(document).on('click', '.add-form-row', function (event) { event.preventDefault(); cloneMore('.form-row:last', 'questions'); }) $(document).on('click', '.remove-form-row', function (event) { event.preventDefault(); deleteForm('questions', $(this)); }); </script> Here's a photo of what it should look like Again, I want it to be possible to add questions, remove them, save the form. And after I click on the poll in the list of all polls and go to it's edit page I want already added questions to be there. UPDATE Found solution to MultiValueDictKeyError in this post How to debug a Django MultiValueDictKeyError on Formset POST Now the only problem I have is removing Questions from Poll. My delete button works, it removes the form from page, but after saving the document it reappears.
I cannot connect my form to my models for posting of grades
Models.py class YearLevel(models.Model): ... class Section(models.Model): ... class Subject(models.Model): ... class Student(models.Model): first_name = models.CharField(max_length = 100, default = '') last_name = models.CharField(max_length = 100, default = '') year_level = models.OneToOneField(YearLevel, on_delete=models.SET_NULL, null = True) section = models.OneToOneField(Section, on_delete=models.SET_NULL, null = True) enrolled_subject = models.ManyToManyField(Subject) parent = models.ForeignKey(Parent, on_delete=models.SET_NULL, null = True) #parent is from user models class StudentGrade(models.Model): PERIOD_CHOICES = [ ... ] student = models.ForeignKey(Student, on_delete=models.CASCADE,) period = models.CharField(choices=PERIOD_CHOICES, max_length = 30) subjects = models.ForeignKey(Subject, on_delete=models.CASCADE) grade = models.DecimalField(default = 75.00, max_digits=4, decimal_places=2) Views.py def postgrade(request): students = Student.objects.all().prefetch_related('enrolled_subject') context = { 'students': students, } if request.method == "POST": data = request.POST grade_list = data.getlist('grade') subject_list = data.getlist('subject') student = Student.objects.get(pk= data.get('studentid')) #this is where they point my error i=0 while i < len(grade_list): enrolled_subject = Subject.objects.get(pk= subject_list[i]) new_grade = StudentGrade(student = student, period= data.get('period'), subjects = enrolled_subject, grade=grade_list[i]) new_grade.save() i+= 1 Postgrade.html(template) My queries are displaying properly, the problem is I get an error when i try to save the form {% for students in students %} <p> <a class="btn btn-primary" data-bs-toggle="collapse" href="#collapse{{forloop.counter}}" role="button" aria-expanded="false" aria-controls="collapse{{forloop.counter}}"> {{students.first_name}} {{students.last_name}} </a> </p> <div class="collapse" id="collapse{{forloop.counter}}"> <div class="card card-body"> <form method="POST" > {% csrf_token %} <input type="hidden" name="studentid" value="{{students.student.id}}"> <label for="period">Period:</label> <select name="period" required> <option selected>First Grading</option> <option>Second Grading</option> <option>Third Grading</option> <option>Fourth Grading</option> </select><br> {% for subject in students.enrolled_subject.all %} <input type="hidden" name="subject" value="{{subject.id}}"> <label for="{{subject.subject_name}}">{{subject.subject_name}}</label> <input type="text" name="grade"> <br> {% endfor %} <button type="submit">upload grade</button> </form> </div> </div> {% endfor %} My error says: ValueError at /Information/postgrade/ invalid literal for int() with base 10: '' and it points to my views.py: student = Student.objects.get(pk= data.get('studentid')) So i feel like there might be something wrong with my template or views, or maybe both or I should drop out LOL Thanks for the help