How can I pass modelformset_factory validation in Django? - python

I have 2 two models with a one-to-one relation as follow.
class Kategori(models.Model):
urun = models.CharField(db_column='Urun', max_length=255, blank=True, null=True) # Field name made lowercase.
kategori = models.CharField(db_column='Kategori', max_length=255, blank=True, null=True) # Field name made lowercase.
ust_kategori = models.CharField(db_column='Ust_Kategori', max_length=255, blank=True, null=True) # Field name made lowercase.
urun_adi = models.CharField(db_column='URUN_ADI', max_length=255, blank=True, null=True) # Field name made lowercase.
ur_id = models.CharField(db_column='UR_ID', max_length=255, blank=True, null=True) # Field name made lowercase.
marka = models.CharField(db_column='MARKA', max_length=255, blank=True, null=True) # Field name made lowercase.
cesidi = models.CharField(db_column='CESIDI', max_length=255, blank=True, null=True) # Field name made lowercase.
miktar = models.FloatField(db_column='MIKTAR', blank=True, null=True) # Field name made lowercase.
birim = models.CharField(db_column='BIRIM', max_length=255, blank=True, null=True) # Field name made lowercase.
adet = models.FloatField(db_column='ADET', blank=True, null=True) # Field name made lowercase.
class categoryprob(models.Model):
urun = models.OneToOneField(Kategori,on_delete=models.CASCADE,related_name="prob")
kategori = models.CharField(max_length=255, blank=True, null=True) # Field name made lowercase.
ust_kategori = models.CharField(max_length=255, blank=True, null=True) # Field name made lowercase.
urun_adi = models.CharField(max_length=255, blank=True, null=True) # Field name made lowercase.
marka = models.CharField(max_length=255, blank=True, null=True) # Field name made lowercase.
cesidi = models.CharField(max_length=255, blank=True, null=True) # Field name made lowercase.
miktar = models.FloatField(blank=True, null=True) # Field name made lowercase.
birim = models.CharField(max_length=255, blank=True, null=True) # Field name made lowercase.
adet = models.FloatField(blank=True, null=True) # Field name made lowercase.
I am trying to update Kategori model objects depend on categoryprob inputs. I prepare a form to get Kategori objects depend on their probability at categoryprob as follows.
from django import forms
from mailservice.models import categoryprob,Kategori
PASS_PROB = 0.8
class predictionForm(forms.ModelForm):
class Meta:
model = Kategori
fields = ["urun","kategori","ust_kategori","urun_adi","marka","cesidi","miktar","birim","adet"]
widgets = {
'kategori': forms.Select(choices=set(Kategori.objects.all().values_list('kategori','kategori'))),
'ust_kategori': forms.Select(choices=set(Kategori.objects.all().values_list('ust_kategori','ust_kategori'))),
'marka': forms.Select(choices=set(Kategori.objects.all().values_list('marka','marka'))),
'cesidi': forms.Select(choices=set(Kategori.objects.all().values_list('cesidi','cesidi'))),
'miktar': forms.Select(choices=set(Kategori.objects.all().values_list('miktar','miktar'))),
'birim': forms.Select(choices=set(Kategori.objects.all().values_list('birim','birim'))),
'adet': forms.Select(choices=set(Kategori.objects.all().values_list('adet','adet'))),
}
labels ={
'urun':""
}
def __init__(self, *args, **kwargs):
super(predictionForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
prob = categoryprob.objects.get(urun=instance)
self.fields['urun'].widget.attrs['readonly'] = True
if float(prob.kategori) > PASS_PROB:
self.fields['kategori'].widget.attrs['disabled'] = True
self.fields['kategori'].widget.attrs['style'] = 'border-color:red'
else:
self.fields['kategori'].widget.attrs['style'] = 'border-color:green'
if float(prob.ust_kategori) > PASS_PROB:
self.fields['ust_kategori'].widget.attrs['disabled'] = True
self.fields['ust_kategori'].widget.attrs['style'] = 'border-color:red'
else:
self.fields['ust_kategori'].widget.attrs['style'] = 'border-color:green'
if float(prob.urun_adi) > PASS_PROB:
self.fields['urun_adi'].widget.attrs['disabled'] = True
self.fields['urun_adi'].widget.attrs['style'] = 'border-color:red'
else:
self.fields['urun_adi'].widget.attrs['style'] = 'border-color:green'
if float(prob.marka) > PASS_PROB:
self.fields['marka'].widget.attrs['disabled'] = True
self.fields['marka'].widget.attrs['style'] = 'border-color:red'
else:
self.fields['marka'].widget.attrs['style'] = 'border-color:green'
if float(prob.cesidi) > PASS_PROB:
self.fields['cesidi'].widget.attrs['disabled'] = True
self.fields['cesidi'].widget.attrs['style'] = 'border-color:red'
else:
self.fields['cesidi'].widget.attrs['style'] = 'border-color:green'
if float(prob.miktar) > PASS_PROB:
self.fields['miktar'].widget.attrs['disabled'] = True
self.fields['miktar'].widget.attrs['style'] = 'border-color:red'
else:
self.fields['miktar'].widget.attrs['style'] = 'border-color:green'
if float(prob.birim) > PASS_PROB:
self.fields['birim'].widget.attrs['disabled'] = True
self.fields['birim'].widget.attrs['style'] = 'border-color:red'
else:
self.fields['birim'].widget.attrs['style'] = 'border-color:green'
if float(prob.adet) > PASS_PROB:
self.fields['adet'].widget.attrs['disabled'] = True
self.fields['adet'].widget.attrs['style'] = 'border-color:red'
else:
self.fields['adet'].widget.attrs['style'] = 'border-color:green'
I use modelformset_factory to render 3 of them together. Everything works fine when I am rending on the template as follows.
<form method="post" enctype="multipart/form-data">
<div class="form-row">
{{ p_form.management_form }}
{% csrf_token %}
{%for form in p_form%}
<div class="form-group col-md-12">
<div class="card">
<div class="card-header">
{{form.urun|as_crispy_field}}
</div>
<div class="card-body">
<div class="row">
<div class ="col-md-3 col ">
{{form.kategori|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.ust_kategori|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.urun_adi|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.marka|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.cesidi|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.miktar|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.birim|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.adet|as_crispy_field}}
</div>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
<button type="submit" class="btn btn-success">Kaydet</button>
</form>
When I submit with post method as follows:
def editCategories(request):
categories = Kategori.objects.all().order_by('?')[:3]
CategoryFormSet = modelformset_factory(Kategori, form = predictionForm,extra=0)
formset = CategoryFormSet(queryset = categories)
if request.method == "POST":
if formset.is_valid():
formset.save()
return redirect(request.META['HTTP_REFERER'])
content = {
"p_form":formset,
}
return render(request,'edit_categories.html',content)
formset.is_valid return false all the time.
I couldn't figure out how to validate all forms at once. Do you have any suggestion?
Picture of template output:
The output of the request.POST:
<QueryDict: {'form-TOTAL_FORMS': ['3'], 'form-INITIAL_FORMS': ['3'], 'form-MIN_NUM_FORMS': ['0'], 'form-MAX_NUM_FORMS': ['1000'], 'csrfmiddlewaretoken': ['*****'], 'form-0-id': ['125'], 'form-0-urun': ['_MotorinEcoForce'], 'form-0-urun_adi': ['asdasd'], 'form-1-id': ['186'], 'form-1-urun': ['7 stick sakız karpuz aromalı 12 adet'], 'form-1-marka': ['7 days'], 'form-2-id': ['159'], 'form-2-urun': ['7 Days Kruvasan Kayısılı Tekli 72 g'], 'form-2-kategori': ['Sebze']}>

One can say there are two kinds of forms a bound form and an unbound form. What is the difference between these? Well a bound form is passed some data MyForm(request.POST, request.FILES) and an unbound form isn't passed any data MyForm(). By logic an unbound form can never be valid because, well it was never submitted and it is assumed to be created to simply display / render the form.
This logic similarly follows for formsets, and hence as you haven't passed any data to your formset it will never be valid. Another thing to be considered is that you haven't rendered the hidden fields for the formset. A formset makes certain hidden fields so that it can recognize which sub form is for which objects and some other things like deletion, etc. Without these hidden fields also your formset would be invalid.
Hence your view should be like:
def editCategories(request):
categories = Kategori.objects.all().order_by('?')[:3]
CategoryFormSet = modelformset_factory(Kategori, form = predictionForm,extra=0)
formset = CategoryFormSet(queryset = categories)
if request.method == "POST":
# Will get inefficient later on when you have many objects in the database, look for a different solution
formset = CategoryFormSet(request.POST, request.FILES) # Make a bound formset in case of a POST request
if formset.is_valid():
formset.save()
return redirect(request.META['HTTP_REFERER'])
content = {
"p_form":formset,
}
return render(request,'edit_categories.html',content)
Your template should be like:
<form method="post" enctype="multipart/form-data">
<div class="form-row">
{{ p_form.management_form }}
{% csrf_token %}
{%for form in p_form%}
{# Render hidden fields #}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
<div class="form-group col-md-12">
<div class="card">
<div class="card-header">
{{form.urun|as_crispy_field}}
</div>
<div class="card-body">
<div class="row">
<div class ="col-md-3 col ">
{{form.kategori|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.ust_kategori|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.urun_adi|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.marka|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.cesidi|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.miktar|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.birim|as_crispy_field}}
</div>
<div class ="col-md-3 col">
{{form.adet|as_crispy_field}}
</div>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
<button type="submit" class="btn btn-success">Kaydet</button>
</form>
Also you set fields to be disabled only by adding a disabled attribute to their widget, this means they are not posted with the form, but since the field itself is not disabled it looks for their data, doesn't find it and sets it to None, instead you want to disable the field itself:
class predictionForm(forms.ModelForm):
...
def __init__(self, *args, **kwargs):
...
# truncated for shortness
# similar needs to be done for other fields too
if float(prob.kategori) > PASS_PROB:
self.fields['kategori'].disabled = True
self.fields['kategori'].widget.attrs['style'] = 'border-color:red'
...

Related

Reverse for 'delete' with arguments '('',)' not found. 1 pattern(s) tried: ['delete/(?P<slug>[^/]+)/\\Z']

Been stuck at this trying to delete data from the database, I'm clearly lost with the logic somewhere I'd grately appreciate any assistance.
resume-detail.html:
<div class="row">
{% if educations %}
{% for education in educations %}
<div class="col-lg-12 mt-4 pt-2">
<div class="component-wrapper rounded shadow">
<div class="p-4 border-bottom bg-light">
<h4 class="title mb-0">{{education.institution}}</h4>
</div>
<div class="p-4">
<div class="row">
<div class="col">
<p><strong>Qualification: </strong> {{education.qualification}}</p>
</div>
<div class="col">
<p><strong>Level of Qualification: </strong> {{education.level}}</p>
</div>
</div>
<div class="row">
<div class="col">
Delete Qualification
<!-- <button class="btn btn-danger">Delete Qualification</button> -->
</div>
</div>
</div>
</div>
</div>
{% endfor %}
{% endif %}
</div>
<div class="row">
<div class="col-lg-12 mt-4 pt-2">
<h4 class="text-dark"><button type="button" class="btn btn-secondary-outline btn-outline-success" data-toggle="modal" data-target="#addEducation"><span class="mr-2">+</span> Add Education</button></h4>
</div>
</div>
i'm using a modal to capture this data
<div class="modal fade" id="addEducation" tabindex="-1" aria-labelledby="addEducationLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<form action="" method="POST">
{% csrf_token %}....
urls.py
path('userapp/view/<slug:slug>/', user_views.resume_detail, name='resume-detail'),
path('delete/<str:id>/', user_views.delete_view, name='delete' )
views.py
def delete_view(request, id):
obj = Resume.objects.get(id = id)
if request.method =="POST":
obj.delete()
messages.success(request,"Information Deleted Successfully")
return redirect('resume-detail', id = id)
educations = Education.objects.get(resume = obj)
experiences = Experience.objects.get(resume = obj)
context = {}
context['object'] = obj
context['educations'] = educations
context['experiences'] = experiences
return render(request, 'resume-detail.html', context)
I would like to delete data for educations and experiences. Its the data I capture with the modals. What could I be doing wrong ?
models.py
class Resume(models.Model):
user = models.OneToOneField(User, on_delete = models.CASCADE)
uniqueId = models.CharField(null=True, blank=True, max_length=200)
image = models.ImageField(default = 'default.jpg', upload_to='profile_images')
email_confirmed = models.BooleanField(default=False)
date_birth = models.DateField(blank=True, null=True)
sex = models.CharField(choices=SEX_CHOICES, default=OTHER, max_length=200)
marital_status = models.CharField(choices=MARITAL_CHOICES, default=SINGLE, max_length=200)
addressLine1 = models.CharField(null=True, blank=True, max_length=200)
addressLine2 = models.CharField(null=True, blank=True, max_length=200)
village = models.CharField(null=True,blank=True, max_length=200)
city = models.CharField(null=True, blank=True, choices=DISTRICT_CHOICES, default=KAMPALA, max_length=200)
district = models.CharField(choices=DISTRICT_CHOICES, default=KAMPALA, max_length=100)
phoneNumber = models.CharField(null=True, blank=True, max_length=200)
slug = models.SlugField(max_length=500, unique=True, blank=True, null=True)
date_created = models.DateTimeField(default= timezone.now)
last_updated = models.DateTimeField(blank=True, null=True)
cover_letter = models.FileField(upload_to='resumes', null=True, blank=True,)
cv = models.FileField(upload_to='resumes', null=True, blank=True,)
def __str__(self):
return '{} {} {}'.format(self.user.first_name, self.user.last_name, self.uniqueId)
def get_absolute_url(self):
return reverse('resume-detail', kwargs={'slug': self.slug})
def save(self, *args, **kwargs):
if self.uniqueId is None:
self.uniqueId = str(uuid4()).split('-')[0]
self.slug = slugify('{} {} {}'.format(self.user.first_name, self.user.last_name, self.uniqueId))
if self.image == 'default.jpg':
self.image = random.choice(self.IMAGES)
self.slug = slugify('{} {} {}'.format(self.user.first_name, self.user.last_name, self.uniqueId))
super(Resume, self).save(*args, **kwargs)
class Education(models.Model):
institution = models.CharField(null=True, max_length=200)
qualification = models.CharField(null=True, max_length=200)
level = models.CharField(choices=LEVEL_CHOICES, default=LEVEL5A, max_length=200)
start_date = models.DateField()
graduated = models.DateField()
major_subject = models.CharField(null=True, max_length=200)
date_created = models.DateTimeField(default = timezone.now)
resume = models.ForeignKey(Resume, on_delete=models.CASCADE)
def __str__(self):
return '{} for {} {}'.format(self.qualification, self.resume.user.first_name, self.resume.user.last_name)
class Experience(models.Model):
company = models.CharField(null = True, max_length=200)
position = models.CharField(null = True, max_length=200)
start_date = models.DateField()
end_date = models.DateField()
experience = models.TextField()
skills = models.TextField()
resume = models.ForeignKey(Resume, on_delete = models.CASCADE)
def __str__(self):
return '{} at {}'.format(self.position, self.company)
You need to give id which is primary key in the Education model, so:
<form action="{% url 'delete' educations.id %}" method="POST">
{% csrf_token %}....
Add education as ForeignKey in the model, so:
class Resume(models.Model):
education=models.ForeignKey(Education,on_delete=models.CASCADE)
Change the url as:
path('userapp/view/<int:id>/', user_views.resume_detail, name='resume-detail'),
path('delete/<int:id>/', user_views.delete_view, name='delete' )
Then in view, get the object through id then delete it.
from django.shortcuts import get_object_or_404
def delete_view(request, id):
education_instance=get_object_or_404(Education,id=id)
obj = get_object_or_404(Resume, education=education_instance)
if request.method =="POST":
obj.delete()
messages.success(request,"Information Deleted Successfully")
return redirect('resume-detail', id=id)
educations = get_object_or_404(Education, resume=obj)
experiences = get_object_or_404(Experience,resume=obj)
context = {}
context['object'] = obj
context['educations'] = educations
context['experiences'] = experiences
return render(request, 'resume-detail.html', context)
Note: Generally, it is better to use get_object_or_404() instead of get() as it calls get() on a given model manager, but it raises Http404 instead of the model’s DoesNotExist exception.
As #SunderamDubey said, if you need objects Education and Experience based by the Resume relation - edit your urls.py path to accept delete/<int:resume_pk> instead of delete/<str:slug>/.
Then:
# urls.py
path('delete/<int:resume_pk>/', user_views.delete_view, name='delete')
# views.py
def delete_view(request, resume_pk):
obj = Resume.objects.get(id=resume_pk)
...
educations = Education.objects.get(resume=obj)
experiences = Experience.objects.get(resume=obj)
...
# modal
<form action="{% url 'delete' resume_pk=obj.pk %}" method="POST">

django clean method is not being called when validating form

I tried the simplest way of form validation I could find using the clean method (I need to validate multiple fields). However, it is not working and it is not throwing any errors.
forms.py
class DOEForm1(ModelForm):
class Meta:
model = Doe
labels = {
'column_parameter': ('Parameter to vary'),
'column_min': ('Minimum value'),
'column_max': ('Maximum value'),
'column_step': ('Step value'),
}
exclude = ('substrate','row_parameter','row_min','row_max','row_step',)
def clean(self):
cleaned_data = super().clean()
print('test')
min = cleaned_data.get('column_min')
max = cleaned_data.get('column_max')
step = cleaned_data.get('column_step')
if min and max and step:
if not (int(step) > 10):
raise ValidationError(
'(!) the parameters you inputted dont go well with the substrate size'
)
return cleaned_data
template
{% extends 'accounts/main.html' %}
{% load static %}
{% block content %}
<br>
<div class="row" style = "padding-left: 15px; width: 500px; margin: auto;">
<div class="col" style = "margin: auto; ">
<div class="card card-body">
<form style = "margin: auto; width: 400px; padding: 20px; border: 1px solid #270644;" action="" method="POST">
{% csrf_token %}
<table>
{{ St_form.as_table }}
{{ DOE_form.as_table }}
</table>
{% for error in form.non_field_errors %}
<p class = "help is-danger">{{ error }}</p>
{% endfor %}
<input type="submit" name="Submit" >
</form>
</div>
</div>
</div>
{% endblock %}
views.py
def ST_parameters(request):
st_form = STForm()
doe_form = DOEForm1()
if request.method == 'POST':
#print('Printing POST: ', request.POST)
st_form = STForm(request.POST)
doe_form = DOEForm1(request.POST)
if st_form.is_valid() and doe_form.is_valid():
st = st_form.save()
doe = doe_form.save(False)
doe.st=st
doe.save()
return redirect('user-page')
context ={'St_form':st_form,'DOE_form':doe_form}
return render(request, 'accounts/ST_form.html',context)
models.py
class Doe(models.Model):
LASER_POWER = "Laser Power"
LASER_SPEED = "Laser speed"
POWDER_FEED="Powder feed rate"
CARRIER_GAS = "Carrier gas"
SHIELD_GAS = "Shield gas"
SPOT_DIAMETER = "Spot Diameter"
NOZZLE_STANDOFF = "Nozzle standoff"
PARAMETER_CHOICES = [
(LASER_POWER, "Laser Power"),
(LASER_SPEED, "Laser Speed"),
(POWDER_FEED, "Powder feed rate"),
(CARRIER_GAS, "Carrier Gas"),
(SHIELD_GAS,"Shield Gas"),
(SPOT_DIAMETER,"Spot Diameter"),
(NOZZLE_STANDOFF, "Nozzle Standoff")
]
doe_id = models.AutoField(db_column='DoE_ID', primary_key=True)
substrate = models.ForeignKey('Substrate', models.SET_NULL, db_column='Substrate_ID', blank=True, null=True) # Field name made lowercase.
row_parameter = models.CharField(max_length=45, choices = PARAMETER_CHOICES,default = LASER_POWER, blank=True, null=True)
row_min = models.CharField(max_length=45, blank=True, null=True)
row_max = models.CharField(max_length=45, blank=True, null=True)
row_step = models.CharField(max_length=45, blank=True, null=True)
column_parameter = models.CharField(max_length=45,choices = PARAMETER_CHOICES,default = LASER_POWER, blank=True, null=True)
column_min = models.CharField(max_length=45, blank=True, null=True)
column_max = models.CharField(max_length=45, blank=True, null=True)
column_step = models.CharField(max_length=45, blank=True, null=True)
class Meta:
db_table = 'doe'
What am I doing wrong here?
When you work with Django Forms, keep in mind this (simplified) validation flow:
form.is_valid() check if not form.errors
form.errors call form.full_clean()
form.full_clean() clean each single field and after will call form.clean()
So if you want to understand what is happening, debug the value of form.is_valid() and form.errors.

Display of Django ModelForm field validation errors in crispy forms

I am using the following ModelForm:
class ListingQuoteForm(forms.ModelForm):
author_phone = forms.CharField(validators=[validate_phone_number])
content = forms.CharField(
label='Your message',
min_length=50,
widget=forms.Textarea(attrs={'rows': 4}),
help_text='Please provide a few details about your race and your requirements',
)
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
if user.is_authenticated:
self.fields['author_name'].initial = user.full_name(strict=True)
self.fields['author_email'].initial = user.email
self.fields['author_email'].disabled = True
class Meta:
model = QuoteRequest
fields = ('author_name', 'author_email', 'author_phone', 'content')
labels = {
'author_name': 'Your name',
'author_email': 'Your email',
'author_phone': 'Your phone number',
}
and rendering it in the following template:
{% load crispy_forms_tags %}
<div class="listing-section" id="quote-form">
<div class="listing-section-header">
{% if primary_category.quote_request_type == 'quote' %}
<h2>Request a quote</h2>
{% elif primary_category.quote_request_type == 'info' %}
<h2>Request more info</h2>
{% endif %}
</div>
<div class="listing-section-body">
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ quote_form.author_name|as_crispy_field }}
{{ quote_form.author_email|as_crispy_field }}
{{ quote_form.author_phone|as_crispy_field }}
{{ quote_form.content|as_crispy_field }}
<div class="form-group">
<button class="standard-button standard-button--submit" type="submit">Send</button>
</div>
</form>
</div>
</div>
When the content field min length validation fails, a message is displayed like so:
But when my custom phone number validation fails, the error displays under the field like so:
EDIT: Here's the QuoteRequest object as well:
class QuoteRequest(models.Model, ModelMixin):
SOURCES = (
('listing_page', 'Listing page'),
('dashboard_offers', 'Dashboard offers'),
('concierge', 'Concierge'),
)
source = models.CharField(max_length=18, null=True, blank=True, choices=SOURCES)
author = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL, related_name='quote_requests')
author_name = models.CharField(max_length=40)
author_email = models.EmailField()
author_phone = models.CharField(max_length=24, null=True, blank=True, validators=[validate_phone_number])
content = models.TextField()
category = models.ForeignKey(Category, null=True, blank=True, on_delete=models.CASCADE, related_name='quote_requests')
listing = models.ForeignKey(Listing, null=True, blank=True, on_delete=models.CASCADE, related_name='quote_requests')
offer = models.ForeignKey(Offer, null=True, blank=True, on_delete=models.SET_NULL, related_name='quote_requests')
race = models.ForeignKey(Race, null=True, blank=True, on_delete=models.SET_NULL, related_name='quote_requests')
approved = models.BooleanField(default=False)
date_created = models.DateTimeField(auto_now_add=True)
date_approved = models.DateTimeField(null=True)
How can I get my phone number validation error to display the same way the in-built min length validation does for the CharField?
You can use novalidate on form, to off default behavior of html5 of showing errors so that Django's errors can be shown.
So:
<form method="POST" enctype="multipart/form-data" novalidate>
{% csrf_token %}
{{ quote_form.author_name|as_crispy_field }}
{{ quote_form.author_email|as_crispy_field }}
{{ quote_form.author_phone|as_crispy_field }}
{{ quote_form.content|as_crispy_field }}
<div class="form-group">
<button class="standard-button standard-button--submit" type="submit">Send</button>
</div>
</form>

Store multiple inputs values of form in single json to store in model field. - Django

I am working on a project which is online printing ordering service.
Here on the order page I am getting different attributes of product in radio button list in the form, and all the attributes I want to store in a single json in database.
models.py
class Product(models.Model):
prod_ID = models.AutoField("Product ID", primary_key=True)
prod_Name = models.CharField("Product Name", max_length=30, null=False)
prod_Desc = models.CharField("Product Description", max_length=2000, null=False)
prod_Price = models.IntegerField("Product Price/Piece", default=0.00)
prod_img = models.ImageField("Product Image", null=True)
def __str__(self):
return "{}-->{}".format(self.prod_ID,
self.prod_Name)
# this is the order table , there is a "attribute_field" I wantto store the attributes in this field
# as JSON.
class Order(models.Model):
order_id = models.AutoField("Order ID", primary_key=True)
user_id = models.ForeignKey(User, on_delete=models.CASCADE, null=False, verbose_name="Customer ID")
prod_id = models.ForeignKey(Product, on_delete=models.CASCADE, null=False, verbose_name="Product ID")
quantity = models.ImageField('Product Quantity', max_length=10, default=500)
attribute_value = models.CharField("Item Details JSON", max_length=2000, null=False)
order_date = models.DateField("Order Date", auto_now_add=True, null=False)
order_job_title = models.CharField("Name of Company/Business", max_length=100, null=False)
order_desc = models.CharField("Details for Product", max_length=1000, null=False)
product_img = models.ImageField("Template Image", null=False)
address = models.CharField("Customer Address ", max_length=100, null=False)
state = models.CharField("Customer State", max_length=30, null=False)
city = models.CharField("Customer City", max_length=30, null=False)
postal_code = models.IntegerField("Area Pin Code", null=False)
order_price = models.DecimalField(max_digits=8, decimal_places=2, default=0000.00)
class Size(models.Model):
size_id = models.AutoField("Size ID", primary_key=True, auto_created=True)
prod_size = models.CharField("Product Size", max_length=20, null=False)
def __str__(self):
return "{size_id}-->{prod_size}".format(size_id=self.size_id,
prod_size=self.prod_size)
class Color(models.Model):
color_id = models.AutoField("Color ID", primary_key=True, auto_created=True)
prod_color = models.CharField("Product Color", max_length=50, null=False)
def __str__(self):
return "{color_id}-->{prod_color}".format(color_id=self.color_id,
prod_color=self.prod_color)
class PaperChoice(models.Model):
paper_id = models.AutoField("Paper Choice ID", primary_key=True, auto_created=True)
paper_choices_name = models.CharField("Paper Choices", max_length=50, null=False)
def __str__(self):
return "{}-->{}".format(self.paper_id,
self.paper_choices_name)
class SizeProductMapping(models.Model):
size_p_map_id = models.AutoField("Size & Product Map ID", primary_key=True, auto_created=True)
size_id = models.ForeignKey(Size, null=False, on_delete=models.CASCADE, verbose_name="Size ID")
prod_id = models.ForeignKey(Product, null=False, on_delete=models.CASCADE, verbose_name="Product Id")
class ColorProductMapping(models.Model):
color_p_map_id = models.AutoField("Color & Product Map ID", primary_key=True, auto_created=True)
color_id = models.ForeignKey(Color, null=False, on_delete=models.CASCADE, verbose_name="Color ID")
prod_id = models.ForeignKey(Product, null=False, on_delete=models.CASCADE, verbose_name="Product Id")
class PaperChoiceProductMapping(models.Model):
paper_p_map_id = models.AutoField("Paper Choices & Product Map ID", primary_key=True, auto_created=True)
paper_id = models.ForeignKey(PaperChoice, null=False, on_delete=models.CASCADE, verbose_name="Paper ID")
prod_id = models.ForeignKey(Product, null=False, on_delete=models.CASCADE, verbose_name="Product Id")
this is my views.py and it is incomplete , I want to store the forms data in the model using this
view.
views.py
#here in thi view method I am only getting data from models but not getting template data to store in the the model,
# I know I haven't taken inputs from the form here
# I haven't done because I don't know what logic I should use here.
def order(request, id):
products = Product.objects.all()
sizesList = []
ColorsList = []
PaperChoiceProductsList = []
try:
sizesMap = SizeProductMapping.objects.filter(prod_id=id)
sizesList = [data.size_id.prod_size for data in sizesMap]
except AttributeError:
pass
try:
colorMap = ColorProductMapping.objects.filter(prod_id=id)
ColorsList = [data.color_id.prod_color for data in colorMap]
except AttributeError:
pass
try:
PaperChoiceProductMap = PaperChoiceProductMapping.objects.filter(prod_id=id)
PaperChoiceProductsList = [data.paper_id.paper_choices_name for data in PaperChoiceProductMap]
except AttributeError:
pass
context = {'products': products,
'sizesList': sizesList,
"ColorsList": ColorsList,
"PaperChoiceProductsList": PaperChoiceProductsList,
}
return render(request, 'user/order.html', context)
order.html
{% extends 'user/layout/userMaster.html' %}
{% block title %}Order{% endblock %}
{% block css %}
form
{
position:relative;
}
.tasksInput
{
margin-right:150px;
}
label
{
vertical-align: top;
}
{% endblock %}
{% block header %}
{% endblock %}
{% block main %}
<div class="container">
<div>
<div class="row rounded mx-auto d-block d-flex justify-content-center">
<button class="btn btn-secondary my-2 mr-1">Custom</button>
<button class="btn btn-secondary my-2 ml-1">Package</button>
</div>
<div class="row">
<div class="col-4">
<div class="card border border-secondary">
<div class="card body mx-2 mt-4 mb-2">
{% for product in products %}
<a id="{{ product.prod_ID }}" class="card-header" style="font-size:5vw;color:black;"
href="{% url 'user-order' product.prod_ID %}">
<h5 class="h5">{{ product.prod_ID }}. {{ product.prod_Name }}</h5></a>
<div class="dropdown-divider"></div>
{% endfor %}
</div>
</div>
</div>
<div class="col-8">
<form>
<div class="card mx-2 my-2 border border-secondary">
<div class="my-2">
<!-- The data I want to store in JSON starts from here -->
{% if sizesList %}
<div class="form-group">
<div class="form-group row mx-2">
<label for="sizeList"
class="form-control-label font-weight-bold card-header col-4 ml-4"
style="background-color:#e3e4e6"><h5>Sizes : </h5></label>
<div id="sizeList">
{% for s in sizesList %}
<input id="{{s}}" class="mx-2 my-auto" type="radio" name="size">
<label for="{{s}}">{{s}}</label><br>
{% endfor %}
</div>
</div>
</div>
{% endif %}
{% if ColorsList %}
<div class="form-group">
<div class="form-group row mx-2">
<label for="ColorsList"
class="form-control-label font-weight-bold card-header col-4 ml-4"
style="background-color:#e3e4e6"><h5>Colors : </h5></label>
<div id="ColorsList">
{% for c in ColorsList %}
<input id="{{c}}" class="mx-2 my-auto" type="radio" name="Color">
<label for="{{c}}">{{c}}</label><br>
{% endfor %}
</div>
</div>
</div>
{% endif %}
{% if PaperChoiceProductsList %}
<div class="form-group">
<div class="form-group row mx-2">
<label for="ColorsList"
class="form-control-label font-weight-bold card-header col-4 ml-4"
style="background-color:#e3e4e6"><h5>Paper Choice : </h5></label>
<div id="PaperChoiceProductsList">
{% for pc in PaperChoiceProductsList %}
<input id="{{pc}}" class="mx-2 my-auto" type="radio" name="PaperChoice">
<label for="{{pc}}">{{pc}}</label><br>
{% endfor %}
</div>
</div>
</div>
{% endif %}
<!-- The Data I want to store in the JSON ends here -->
</div>
</div>
</div>
</form>
</div>
</div>
<div class="row rounded mx-auto d-block d-flex justify-content-center">
<button class="btn btn-success my-2">Place Order</button>
</div>
</div>
</div>
{% endblock %}
As mentioned in above template comment I want to store that data in single JSON.
Can you please help me to create a view for it.
urls.py
path('order/<int:id>', views.order, name="user-order"),
I used jason dump method to store value in single json object and then passed it to the field and it is working for me.
views.py
import json
def order(request, id):
products = Product.objects.all()
sizesList = []
ColorsList = []
PaperChoiceProductsList = []
value = {}
try:
sizesMap = SizeProductMapping.objects.filter(prod_id=id)
sizesList = [data.size_id.prod_size for data in sizesMap]
except AttributeError:
pass
try:
colorMap = ColorProductMapping.objects.filter(prod_id=id)
ColorsList = [data.color_id.prod_color for data in colorMap]
except AttributeError:
pass
try:
PaperChoiceProductMap = PaperChoiceProductMapping.objects.filter(prod_id=id)
PaperChoiceProductsList = [data.paper_id.paper_choices_name for data in PaperChoiceProductMap]
except AttributeError:
pass
if request.method == 'POST':
if request.method == 'POST':
customer_id = request.user
product = Product.objects.get(prod_ID=id)
product_id = product
try:
quantity = request.POST['quantity']
print(quantity)
except MultiValueDictKeyError:
pass
try:
size = request.POST['size']
value.update(size=size)
except MultiValueDictKeyError:
pass
try:
Colour = request.POST['Color']
value.update(Colour=Colour)
except MultiValueDictKeyError:
pass
try:
Paper_Choice = request.POST['PaperChoice']
value.update(Paper_Choice=Paper_Choice)
except MultiValueDictKeyError:
pass
attribute_value = json.dumps(value)
order_store = Order(user_id=customer_id, prod_id=product_id, quantity=quantity, attribute_value=attribute_value,
order_job_title=Job_title, order_desc=Order_Detail, address=User_Address, state=State,
city=City, postal_code=Postal_Code, product_img=TemplateValue)
order_store.save()
context = {'products': products,
'sizesList': sizesList,
"AqutousCoatingProductList": AqutousCoatingProductList,
"ColorsList": ColorsList,
"PaperChoiceProductsList": PaperChoiceProductsList,
}
return render(request, 'user/order.html', context)

Foreign Key value assigning in Django

I am working on a project in Django where two custom build user model is used.
Industry
Employee
Here every Industry user will entry some of their Employee's data, and later on Employee will verify and finish to create his account.
my models.py:
class myCustomeUser(AbstractUser):
id = models.AutoField(primary_key=True)
username = models.CharField(max_length=20, unique="True", blank=False)
password = models.CharField(max_length=20, blank=False)
is_Employee = models.BooleanField(default=False)
is_Inspector = models.BooleanField(default=False)
is_Industry = models.BooleanField(default=False)
is_Admin = models.BooleanField(default=False)
class Industry(models.Model):
user = models.OneToOneField(myCustomeUser, on_delete=models.CASCADE, primary_key=True, related_name='industry_releted_user')
name = models.CharField(max_length=200, blank=True)
owner = models.CharField(max_length=200, blank=True)
license = models.IntegerField(null=True, unique=True)
industry_extrafield = models.TextField(blank=True)
class Employee(models.Model):
user = models.OneToOneField(myCustomeUser, on_delete=models.CASCADE, primary_key=True, related_name='employee_releted_user', blank=True)
#industry = models.OneToOneField(Industry, on_delete=models.CASCADE, related_name='employee_releted_industry')
industry = models.ForeignKey(Industry, on_delete=models.CASCADE)
i_id = models.IntegerField(null=True, blank=False, unique=True)
name = models.CharField(max_length=200, blank=False, null=True)
gmail = models.EmailField(null=True, blank=False, unique=True)
rank = models.CharField(max_length=20, blank=False, null=True)
employee_varified = models.BooleanField(default=False, blank=True)
Now I wrote the following code in views.py to create an Employee's entry by Industry user when the Industry user signed in from their account:
#method_decorator(industry_required, name='dispatch')
class industryDetails(DetailView):
model = Industry
template_name = 'app/industryDetails.html'
def get_queryset(self):
return Industry.objects.filter(user=self.request.user)
def get_object(self):
return get_object_or_404(Industry, user=self.request.user)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['inserted_text'] = "inserted text from EmployeeDetails of views.py"
return context
def employeeRegister_byIndustry(request):
employeeRegister_dict={
'insert_me' : "hello this is extra inserted"
}
if request.method == "POST":
this_i_id = request.POST['i_id']
this_name = request.POST['name']
this_rank = request.POST['rank']
this_gmail = request.POST['gmail']
this_industry = self.request.user.industry_releted_user
employee_obj = Employee.objects.create(industry=this_industry, i_id=this_i_id, name=this_name, rank=this_rank, gmail=this_gmail)
employee_obj.save()
if employee_obj.is_valid():
print('valid employee Object')
return redirect('app:employeeSignup')
return render(request, 'app/employeeSignup.html', employeeRegister_dict)
and my template (industryDetails.html):
<div class="container-fluid">
<div class="row m-0">
<div class="col-xl-10 mx-auto">
<p>inserted text: {{ inserted_text }}</p>
<hr>
<h3>Username: {{ industry.user }}</h3>
<p>name: {{ industry.name }}</p>
<p>owner: {{ industry.owner }}</p>
<p>license: {{ industry.license }}</p>
<p>id: {{ industry.user.id }}</p>
<p>username: {{ industry.user.username }}</p>
<p>password: {{ industry.user.password }}</p>
</div>
</div>
</div>
<div class="my-5"></div>
<hr>
<div class="my-5"></div>
<div class="container-fluid">
<div class="row m-0">
<div class="col-xl-8">
</div>
<div class="col-xl-3">
<h3>Add new Employee</h3>
<form class="" action="{% url 'app:employeeRegister_byIndustry' %}" method="post">
{% csrf_token %}
<div class="form-group">
<label>Enter industrial id</label>
<input type="text" class="form-control" name="i_id" placeholder="Industrial id">
</div>
<div class="form-group">
<label>Enter employee name</label>
<input type="text" class="form-control" name="name" placeholder="Employee name">
</div>
<div class="form-group">
<label>rank</label>
<input type="text" class="form-control" name="rank" placeholder="rank">
</div>
<div class="form-group">
<label>Enter employee's gmail</label>
<input type="email" class="form-control" name="gmail" placeholder="gmail">
</div>
<button type="submit" class="btn btn-primary" name="button">Submit</button>
</form>
</div>
</div>
</div>
But here the Foreign Key assignment does not working as I want. How can I fix it?
self.request.user is a user model object, so in thus case a myCustomUser object, not an Industry object. You can access the related Industry object with:
this_industry = request.user.industry_releted_user
This is thus the name of the relation from Industry to myCustomUser in reverse, the name of that relation is determined by the related_name=… parameter [Django-doc].
I would also advise to make use of ModelForm [Django-doc] to validate and clean user input. A POST request can lack certain data or can be forged, so request.POST will for example not per see contain a value for name. A form makes it convenient to validate that all required data is present, check if the email address is indeed a valid email address, and convert data from a string-like object to a python object that is more specific to the model field.

Categories

Resources