Django ValidationErrors not being displayed - django

I'm applying a validation for the datepicker when the user selects a future date. So far, the form does not save an invalid entry but the problem is that it doesn't display the error message for the field. This is what I've tried so far:
forms.py
class PostPagos(forms.ModelForm):
def clean(self):
cleaned_data = super(PostPagos, self).clean()
fecha = cleaned_data.get('fecha')
hoy = datetime.date.today()
if fecha > hoy:
raise forms.ValidationError(
'La Feha no puede ser mayor al día de hoy')
class Meta:
model = Pagos
fields = ('carro', 'pago', 'fecha', 'semana', 'renta')
widgets = {'fecha': forms.DateInput(attrs={'type': 'date'}),
'semana': forms.DateInput(attrs={'type': 'week'})
}
views.py
class PagosCreate(CreateView):
form_class = PostPagos
template_name = "AC/add_expense.html"
def form_valid(self, form):
object = form.save(commit=False)
object.startweek, object.endweek = self.weekdatetimeconverter(
object.semana)
object.save()
return super(PagosCreate, self).form_valid(form)
def weekdatetimeconverter(self, semana):
d = semana
startweek = datetime.datetime.strptime(d + '-1', "%Y-W%W-%w")
endweek = datetime.datetime.strptime(d + '-0', "%Y-W%W-%w")
return (startweek, endweek)
models.py
class Pagos(models.Model):
carro = models.ForeignKey(
Carros, on_delete=models.CASCADE, blank=False, null=False)
pago = models.DecimalField(max_digits=6, decimal_places=2)
fecha = models.DateField(
auto_now=False, auto_now_add=False, blank=True, null=True)
semana = models.CharField(max_length=20)
startweek = models.DateField(
auto_now=False, auto_now_add=False, blank=True, null=True)
endweek = models.DateField(
auto_now=False, auto_now_add=False, blank=True, null=True)
renta = models.ForeignKey(
Renta, on_delete=models.PROTECT, blank=False, null=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name_plural = "Pagos"
def get_absolute_url(self):
return reverse('pagos')
HTML
{% extends "base.html" %}
{% load widget_tweaks %}
{% block content %}
<div class='container'>
<form method="POST">
{% csrf_token %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form.visible_fields %}
<div class="form-group">
<div class='column'>
<label>{{ field.label_tag }}</label>
{% render_field field class="form-control" %}
{% for error in field.errors %}
<span class="help-block">{{ error }}</span>
{% endfor %}
</div>
</div>
{% endfor %}
<div class="form-group">
<button type="submit" class="btn btn-success">
<span class="glyphicon glyphicon-ok"></span> Save
</button>
Cancel
</div>
</form>
</div>
{% endblock content%}
I'm using django-widget-tweaks

After reading again the documentation [https://docs.djangoproject.com/en/3.0/ref/forms/validation/#cleaning-a-specific-field-attribute][1]
one of my mistakes was that I was not doing a return, and it turns out the code needed was way simple to what I had, here it goes:
forms.py
class PostPagos(forms.ModelForm):
def clean_fecha(self):
fecha = self.cleaned_data['fecha']
if fecha > datetime.date.today():
raise forms.ValidationError(
'La Fecha no puede ser mayor al día de hoy')
return fecha
class Meta:
model = Pagos
fields = ('carro', 'pago', 'fecha', 'semana', 'renta')
widgets = {'fecha': forms.DateInput(attrs={'type': 'date'}),
'semana': forms.DateInput(attrs={'type': 'week'})
}

Related

How to query from 2 Models in Class based views in django?

I have a model Log and another model Solutions and I am using DetailView to display details of each log
Each log can have many solutions.
There is a log field in the Solutions model that is Foreign Key to Log model..
Now how do I access both Log model and Solutions of that particular log in the same html template if I want to display all the solutions of that particular log below the details of the log
models.py:
class Log(models.Model):
title = models.CharField(blank=False, max_length=500)
content = models.TextField(blank=False)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
slug = models.SlugField(max_length=50, null=False, unique=True)
author = models.ForeignKey(User, on_delete=models.CASCADE,null=True, blank=True)
image = models.ImageField(
upload_to='images', blank=True)
def save(self, *args, **kwargs):
super().save()
self.slug = self.slug or slugify(self.title + '-' + str(self.id))
super().save(*args, **kwargs)
class Meta:
verbose_name = ("Log")
verbose_name_plural = ("Logs")
def __str__(self):
return f"{self.title}"
def get_absolute_url(self):
return reverse("log-detail", kwargs={"question": self.slug})
class Solutions(models.Model):
log = models.ForeignKey(
Log, on_delete=models.CASCADE, blank=True, null=True)
author = models.ForeignKey(User, on_delete=models.CASCADE,null=True, blank=True)
solution = models.TextField(null=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
slug = models.SlugField(max_length=50, null=False, blank=True)
image = models.ImageField(
upload_to='images', blank=True)
def save(self, *args, **kwargs):
self.slug = self.slug or slugify(self.solution)
super().save(*args, **kwargs)
class Meta:
verbose_name = ("Solution")
verbose_name_plural = ("Solutions")
def __str__(self):
return f" {self.solution} "
views.py:
class LogDetailView(DetailView):
model = Log
slug_url_kwarg = 'question'
slug_field = 'slug'
log_detail.html:
{% extends 'log/base.html' %}
{%load crispy_forms_tags %}
{% block content %}
<title>Error Logger - {{object.title}}</title>
<div class="main container mt-4 p-3 mb-4">
<img style='display:inline;' class='rounded-circle account-img' src="{{ object.author.profile.avatar.url }}" alt="">
<h1 style='display:inline;'>
{{ object.title }}
</h1>
<p>Author: {{ object.author }}</p>
<p>Date and time of creation: {{ object.created }}</p>
<span> Details </span>:
<p class="big ml-4">{{ object.content }} <br />
{% if object.image %}
<img style="width: 20vw" class="mt-4" src="{{ object.image.url }}" alt="image" />
{% else %}
{% endif %}
</p>
</div>
<br />
<a
class="btn btn-outline btn-info button-solution"
href="#"
>Add solution</a
>
You can enumerate over these in the template by accessing the relation in reverse, this is normally modelname_set, unless you set a related_name=…. So in this case it is solutions_set:
{% for solution in object.solutions_set.all %}
{{ solution }}
{% endfor %}
If the ForeignKey has a related_name=… [Django-doc], for example with:
class Solutions(models.Model):
log = models.ForeignKey(
Log,
on_delete=models.CASCADE,
blank=True,
null=True,
related_name='solutions'
)
# …
Then we access this with:
{% for solution in object.solutions.all %}
{{ solution }}
{% endfor %}
Note: normally a Django model is given a singular name, so Solution instead of Solutions.

DJANGO initial values in form not shown in template (some do some don't)

I have these Models, Tipos, Prioridad and Estado, related to Tarea
as defined below:
class Tipos(models.Model):
tipo = models.CharField(max_length=16,
verbose_name='tipo')
abrv = models.CharField(max_length=4,
null=True,
blank=True,
default='')
class Meta:
verbose_name = "Tipo"
verbose_name_plural = "Tipos"
def __str__(self):
return self.tipo
class Prioridad(models.Model):
prioridad = models.CharField(max_length=16,
verbose_name='prioridad')
abrv = models.CharField(max_length=4,
null=True,
blank=True,
default='')
orden = models.IntegerField(u'orden', blank=False)
class Meta:
verbose_name = "Prioridad"
verbose_name_plural = "Prioridades"
def __str__(self):
return self.prioridad
class Estado(models.Model):
estado = models.CharField(max_length=16,
verbose_name='estado')
abrv = models.CharField(max_length=4,
null=True,
blank=True,
default='')
class Meta:
verbose_name = "Estado"
verbose_name_plural = "Estados"
def __str__(self):
return self.estado
class Tarea(models.Model):
numtar = models.AutoField(primary_key=True)
cliente = models.ForeignKey(User,
related_name='user_cliente',
null=True,
on_delete=models.DO_NOTHING)
apoyo = models.ForeignKey(User,
related_name='user_apoyo',
null=True,
on_delete=models.DO_NOTHING)
asignado = models.ForeignKey(User,
related_name='user_asignado',
null=True,
on_delete=models.DO_NOTHING)
descorta = models.CharField(max_length=140)
deslarga = models.TextField(max_length=8195)
estado = models.ForeignKey(Estado,
null=True,
on_delete=models.SET_NULL)
tipo = models.ForeignKey(Tipos,
null=True,
on_delete=models.SET_NULL)
prioridad = models.ForeignKey(Prioridad,
null=True,
on_delete=models.SET_NULL)
creacion = models.DateTimeField(auto_now_add=True)
revision = models.DateTimeField(auto_now=True, blank=True)
cierre = models.DateTimeField(null=True, blank=True)
class Meta:
verbose_name = "Tarea"
verbose_name_plural = "Tareas"
def __str__(self):
return '%s' % (str(self.numtar))
and I call the following view:
#login_required(login_url='/login')
def newincid_view(request):
perfil = ExUserProfile.objects.get(user=request.user)
prioridad_media = Prioridad.objects.get(prioridad='Media')
estado_abierta = Estado.objects.get(estado='Abierta')
tipo_incidencia = Tipos.objects.get(tipo='Incidencia')
datos_apertura = {'cliente': perfil.user,
'tipo': tipo_incidencia,
'prioridad:': prioridad_media,
'estado': estado_abierta
}
if request.method == 'POST':
form = newincidForm(request.POST,initial=datos_apertura)
if form.is_valid():
tar=form.save(commit=True)
apertura = TipoNota.objects.get(tiponota='Apertura')
anotacion = Nota(numtar=tar, tiponota=apertura,
anotador=perfil.user,
contenido='Incidencia Abierta')
anotacion.save()
else:
form = newincidForm(initial=datos_apertura)
return render(request, "incid/newincid.html", {'form':form})
with this form:
class newincidForm(ModelForm):
class Meta:
model = Tarea
exclude = ['numtar', 'creacion', 'revision', 'cierre']
def __init__(self, *args, **kwargs):
super(newincidForm, self).__init__(*args, **kwargs)
self.fields['descorta'].widget.attrs['class'] = 'form-control no-resize'
self.fields['deslarga'].widget.attrs['class'] = 'form-control no-resize autogrowth'
and this template:
{% extends "incid/base_incid.html" %}
{% load bootstrap3 %}
{% load static %}
{% load logo %}
{% load i18n %} <!-- Hooks para poder hacerlo multilingüe -->
{% load tags_html %}
{% block css %}
{% bootstrap_css %}
{% bootstrap_javascript %}
<link rel="stylesheet"
href="{% static 'adminbsb/plugins/jquery-datatable/skin/bootstrap/css/dataTables.bootstrap.css' %}"/>
{% endblock %}
{% block content %}
<div class="container-fluid">
<div class="row clearfix">
<h4 style="margin-bottom: 10px; margin-top: 10px; padding-left: 15px">NUEVA INCIDENCIA</h4>
</div>
<div class="body">
<form action= "{% url 'incid:newincid' %}" method="post" class="form">
{% csrf_token %}
{% bootstrap_form form %}
{% buttons %}
<button type="submit" class="btn btn-primary">Submit</button>
{% endbuttons %}
</form>
{{ form.errors }}
</div>
</div>
{% endblock %}
extending a standard base with no references to either prioridad, tipo or estado.
Nevertheless, when rendered, tipo and estado show the initial values but prioridad doesn't. I have rewritten view, form and template from scratch twice as I couldn't find a typo but it still happens. I would appreciate any clues or hints on what to do.
Note: This is a revisitation of another problem I posted that I do not know how to delete or edit.
Forget about it. It was something as silly as that I had included the semicolon into the quotes in the datos_apertura definition:
It was written this way:
'prioridad:': prioridad_media,
when it should have been
'prioridad': prioridad_media
Several days lost in such idiocy. An error should raise if I try to initiate an unknown field of a form ,Shouldn't it?. Also if PyCharm didn't take every thing as typos I wouldn't have had it silenced.
Thanks a lot and thanks for the patience in reading my posts.

Django printing dynamic field in template

With a given model:
class Ventas(models.Model):
producto = models.CharField(max_length=200, help_text="", blank=True, null=True)
stock = models.IntegerField(help_text="Tier", blank=True, null=True)
marca = models.ForeignKey(Marcas, help_text="Usuario", blank=True, null=True, on_delete=models.CASCADE)
categoria = models.ImageField(upload_to='', default="", blank=True, null=True)
def __str__(self):
return str(self.producto )
I annotate a queryset using a dynamicaly chosen field as follows:
ventas_producto = ventas.values(ver_por_choices).annotate(
uds_totales=F("uds_totales"),
share=F("uds_totales"),
).order_by('-uds_totales')
The var "ver_por_choices" can take values of the fields of the model: producto, stock, marca or categoria
Then in the template I want to print the values as
{% for venta in ventas_producto %}
<div>{{ venta.uds_totales}}</div>
<div>{{ venta.share}}</div>
{% endfor %}
How can I print the dynamic field?
Why not include it in the queryset as key:
ver_por_choices = 'Some field name'
ventas_producto = ventas.values(ver_por_choices).annotate(
uds_totales=F('uds_totales'),
share=F('uds_totales'),
key=F(ver_por_choices)
).order_by('-uds_totales')
or even more convenient:
ventas_producto = ventas.values(
uds_totales=F('uds_totales'),
share=F('uds_totales'),
key=F(ver_por_choices)
).order_by('-uds_totales')
Then you can usse this in the {% for … %} loop with:
{% for venta in ventas_producto %}
<div>{{ venta.key }}</div>
<div>{{ venta.uds_totales}}</div>
<div>{{ venta.share}}</div>
{% endfor %}

Django 2.2 + DetailView Multiple models with filtering

I'm trying to get my three models working correctly on one DetailView. I have all of them loaded, but the model that contains the images keeps showing the first image. I know I need to filter it somehow, but I don't really know how to do it. Since I need the product info to filter the images. Here is my code:
views:
class VendorDetailView(DetailView):
context_object_name = 'vendor_detail'
model = Vendor
queryset = Vendor.objects.all()
template_name = 'vendor_details.html'
def get_context_data(self, **kwargs):
context = super(VendorDetailView, self).get_context_data(**kwargs)
context['products'] = Product.objects.filter(vendor=self.get_object())
context['image'] = ProductImage.objects.all()
return context
models:
class Product(models.Model):
product_model = models.CharField(max_length=100)
vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE)
slug = models.SlugField(max_length=200, unique=True, null=True)
length = models.CharField(max_length=50)
length_range = models.ForeignKey(LengthRange, on_delete=models.SET_NULL, null=True, blank=True)
hull_type = models.ForeignKey(Hull, on_delete=models.SET_NULL, null=True, blank=True)
max_beam = models.CharField(max_length=50, blank=True, default='0')
cockpit_length = models.CharField(max_length=50, blank=True, default='0')
cockpit_beam = models.CharField(max_length=50, blank=True, default='0')
price = models.DecimalField(decimal_places=2, max_digits=50)
power = models.ForeignKey(PowerConfiguration, on_delete=models.SET_NULL, null=True, blank=True)
average_bare_hull_weight = models.CharField(max_length=50, blank=True, default='0')
fuel_capacity = models.CharField(max_length=50, blank=True, default='0')
seating_capacity = models.ForeignKey(Seat, on_delete=models.SET_NULL, null=True, blank=True)
speed = models.ForeignKey(SpeedRange, on_delete=models.SET_NULL, null=True, blank=True)
warranty = models.CharField(max_length=256, default='None')
hull_only_available = models.BooleanField(blank=False, default=False)
description = models.TextField()
featured = models.BooleanField(blank=False, default=False)
class Meta:
ordering = ['product_model']
def __str__(self):
return '{} {}'.format(self.vendor, self.product_model)
def save(self, *args, **kwargs):
# just check if product_model or vendor.name has changed
self.slug = '-'.join((slugify(self.vendor.name), slugify(self.product_model)))
super(Product, self).save(*args, **kwargs)
class ProductImage(models.Model):
product = models.ForeignKey(Product, related_name='images', on_delete=models.CASCADE)
image = models.ImageField(upload_to='product_images', blank='img/92-thumb.jpg')
class Vendor(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(max_length=200, unique=True, null=True)
website = models.CharField(max_length=256)
vendor_email = models.CharField(max_length=100)
images = models.ImageField(upload_to='vendor_images', blank='img/92-thumb.jpg')
description = models.TextField()
def __str__(self):
return self.name
def save(self, *args, **kwargs):
# just check if product_model or vendor.name has changed
self.slug = slugify(self.name)
super(Vendor, self).save(*args, **kwargs)
Template:
<div class="preview col-md-4">
<div class="vendor-pic">
{% if vendor_detail.images %}
<div class="tab-pane">
<img class="vendor-preview" src="{{ vendor_detail.images.url }}"/></div>
{% endif %}
</div>
**[snipped for brevity]**
</div>
<div class="details col-md-6">
<h3 class="vendor-title">{{ vendor_detail.name }} Boats</h3>
<p class="vendor-description">{{ vendor_detail.description | linebreaksbr }}</p>
<h5 class="website">website: <span>{{ vendor_detail.website }}</span></h5>
</div>
</div>
{% for product in products %}
<div class="product-card">
<div class="product">
<div class="top">{% for product_image in image.all %}
{% if product_image.image %}
<img class="product-img" src="{{ product_image.image.url }}">
{% endif %}
{% endfor %}
</div>
<div class="bottom">
<div class="left">
<div class="details">
<h3>{{ product.vendor }} {{ product.product_model }}</h3>
<p>Starting at ${{ product.price|intcomma }}</p>
</div>
<div class="buy"><a
href="{% url 'boatsales:product_detail' product.slug %}"><i
class="material-icons">pageview</i></a></div>
</div>
</div>
</div>
<div class="inside">
<div class="icon"><i class="material-icons">info_outline</i></div>
<div class="contents">
<p style="text-align: justify">{{ product.description|linebreaksbr }}</p>
</div>
</div>
</div>
{% endfor %}
I've tried multiple ways to filter the product images, but the only thing I can get working is the ProductImages.objects.all() which of course is incorrect. Any help you can provide would be greatly appreciated. Thanks in advance.
You don't need a queryset for the images, you can access them through the Product instances using the related_name like this:
{% for product in products %}
<div class="product-card">
<div class="product">
<div class="top">
{% for product_image in product.images.all %}
<img class="product-img" src="{{ product_image.image.url }}">
{% endfor %}
</div>
...
</div>
{% endfor %}

Django QuerySet FIlter based on previous QuerySet

This may be a simple answer but after days of searching I cannot seem to figure out the correct way to achieve this.
I have a template where I want to show all the questions that are related to an assessment that has been assigned to a user. I thought that I could use the results from:
ResponseDetails = AssessmentResponse.objects.prefetch_related('assessment').filter(id=response_id)
by looking into the object and grabbing the assessment_id which I could then pass into the next query-set as a filter but I couldn't get that to work.
Problem: Because the view doesn't filter based on the assessment_id found in the AssessmentResponse model, it gives me every question in the AssessmentQuestion model.
An answer would allow me to actually have a good nights sleep trying to figure it out.
Views
def UpdateAssessmentResponse(request, response_id):
ResponseDetails = AssessmentResponse.objects.prefetch_related('assessment').filter(id=response_id)
QuestionList = AssessmentQuestion.objects.all()
ChoiceList = AssessmentQuestionChoice.objects.all()
context = {
"ResponseDetails":ResponseDetails,
"QuestionList":QuestionList,
"ChoiceList": ChoiceList,
#"ID" : ID,
}
return render(request, "assessment/assessment_response_update.html", context)
Template
{% if QuestionList and ResponseDetails%}
{% csrf_token %}
{% for question in QuestionList %}
<p> {{ question.question_text }} </p>
{% for choice in ChoiceList %}
{% if choice.question_id == question.pk %}
<fieldset id="group1">
<div class="custom-control custom-radio custom-control-inline">
<input type="radio" class="custom-control-input" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
<label class="custom-control-label" for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label>
</div>
<fieldset id="group1">
{% endif %}
{% endfor %}
{% endfor %}
<div class="card-footer">
<input type="submit" value="Submit" class="btn btn-primary" />
</div>
{% else %}
<p>There are currently no questions for this assessment.</p>
{% endif %}
Models:
class AssessmentForm(models.Model):
name = models.CharField(max_length=400)
description = models.TextField()
created = models.DateTimeField(auto_now_add=True)
is_published = models.BooleanField()
due_date = models.DateField(default=datetime.now, blank=True, null=True)
def __str__(self):
return self.name
class AssessmentResponse(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT)
assessment = models.ForeignKey('AssessmentForm', on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
last_update = models.DateTimeField(auto_now=True)
def get_absolute_url(self):
return reverse('assessment_response_detail', args=[str(self.id)])
#def get_assessment_id(self):
# return self.assessment
def __str__(self):
return self.user
class AssessmentQuestionType(models.Model):
type = models.CharField(max_length=30)
def __str__(self):
return self.type
class AssessmentQuestionCategory(models.Model):
name = models.CharField(max_length=200)
assessment = models.ForeignKey('AssessmentForm', on_delete=models.CASCADE)
def __str__(self):
return self.name
class AssessmentQuestionSubCategory(models.Model):
name = models.CharField(max_length=200)
parent_category = models.ForeignKey('AssessmentQuestionCategory', on_delete=models.CASCADE)
def __str__(self):
return self.name
#CHOICES_HELP_TEXT = _(u"""The choices field is only used if the question type if the question type is 'radio', 'select', or 'select multiple' provide a comma-separated list of options for this question .""")
class AssessmentQuestion(models.Model):
question_type = models.ForeignKey('AssessmentQuestionType', on_delete=models.PROTECT)
question_text = models.TextField()
is_required = models.BooleanField()
category = models.ForeignKey('AssessmentQuestionCategory', on_delete=models.PROTECT, blank=True, null=True)
subcategory = models.ForeignKey('AssessmentQuestionSubCategory', on_delete=models.PROTECT, blank=True, null=True)
assessment = models.ForeignKey('AssessmentForm', on_delete=models.CASCADE)
def __str__(self):
return self.question_text
class AssessmentQuestionChoice(models.Model):
question = models.ForeignKey(AssessmentQuestion, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200, blank=True, null=True)
def __str__(self):
return self.choice_text
class AssessmentAnswer(models.Model):
text = models.CharField(max_length=1024)
question = models.ForeignKey('AssessmentQuestion', on_delete=models.CASCADE)
response = models.ForeignKey('AssessmentResponse', on_delete=models.PROTECT)
def __str__(self):
return self.text
Figured it out! Objects.filter is a lazy query so it wasn't actually available to my other query-set to use as a filter. Solved it by using objects.get instead.