Pre populating a django form using Initial not working - django

I am trying to save a modelform by prepopulating 'template_name' field . As per django documentation and other threads it is clear that initial parameter should work but i just can't make it work for my code. I am getting the error that template_name field is empty. Any help on what am I missing and any other approach towards this will be great. Here is the code
models.py
class TemplateNameModel(models.Model):
"Model to add the template name"
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
tna_template_name = models.CharField(verbose_name="Template name",max_length = 128, unique = True,
null = False, blank = False, help_text="please enter name of the new tna template")
description = models.CharField(verbose_name="template description", max_length = 256,
null = True, blank = True, help_text ="Please enter the description(optional)")
created_by = models.TextField(verbose_name="Template created by", max_length= 128,
null = False, blank = False,help_text ="Please enter the name of creator")
date_created = models.DateTimeField(auto_created= True, null = True, blank = True)
is_active = models.BooleanField(verbose_name="Template status",null = False , blank= False)
def __str__(self):
return self.tna_template_name
class TnaTemplateModel(models.Model):
id = models.AutoField(primary_key=True, editable=False)
template_name = models.ForeignKey(TemplateNameModel, verbose_name="template name", null=False,
blank=False, on_delete=models.CASCADE, help_text="Select the template")
process_name = models.ForeignKey(ProcessModel, verbose_name="process name", null=False,
blank=False, on_delete=models.CASCADE, help_text="Select the process")
sequence = models.IntegerField(verbose_name="Process Sequence",null = False,blank = False)
is_base = models.BooleanField()
formula = models.IntegerField(verbose_name="Formula", null= True,blank = True)
remarks = models.CharField(verbose_name="Process remarks", null= True, blank = True,max_length= 300)
class Meta:
unique_together = ["template_name", "process_name"]
def __str__(self):
return str(self.template_name)
forms.py
class ProcessModelformNew(forms.ModelForm):
class Meta:
model = TnaTemplateModel
fields =('__all__')
views.py
def processcreatenew(request,pk):
template_name = TemplateNameModel.objects.get(id=pk)
if request.method == 'POST':
form = ProcessModelformNew(request.POST)
if form.is_valid():
form.save()
else:
data = {'template_name': template_name}
form = ProcessModelformNew(initial= data)
return render (request,"tna/template_tna/baseprocessmodel_create.html",{'form':form})
Html template
<form role="form" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div class="card-body">
<div class="row">
<div class="col-md-6 col-sm-12">
<!-- text input -->
<div class="form-group">
{{form.process_name|as_crispy_field}}
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-sm-12">
<!-- text input -->
<div class="form-group">
{{form.sequence|as_crispy_field}}
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-sm-12">
<!-- text input -->
<div class="form-group">
{{form.is_base|as_crispy_field}}
</div>
</div>
<div class="col-md-6 col-sm-12">
<!-- text input -->
<div class="form-group">
{{form.formula|as_crispy_field}}
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-sm-12">
<!-- text input -->
<div class="form-group">
{{form.remarks|as_crispy_field}}
</div>
</div>
</div>
</div>
<!-- /.card-body -->
<div class="card-footer">
<button type="submit" class="btn btn-primary">Save</button>
</div>
</form>

You need to render the template_name field in your template so the selected value is passed in the POST data.
{{ form.template_name }}
I suspect you do not want to display the field, you should override it's widget with forms.HiddenInput so that it is not visible to the user
class ProcessModelformNew(forms.ModelForm):
class Meta:
model = TnaTemplateModel
fields = '__all__'
widgets = {'template_name': forms.HiddenInput()}

First method
Include {{ form.template_name }} in your HTML even though you're not want to edit it, just make it hidden
Second method
In your forms.py instead of fields =('__all__') you can put exclude = ['template_name'] so it will no longer required, then in views.py
obj = form.save(commit=False)
obj.template_name = template_name
obj.save()
So if you don't want to include template_name in HTML the second method is good to go, also you don't have to initiate the form

forms.py
def __init__(self, *args, **kwargs):
template_name = kwargs.pop('template_name',None)
self.fields['template_name']= template_name
views.py
inside your model form
def processcreatenew(request,pk):
template_name = TemplateNameModel.objects.get(id=pk)
if request.method == 'POST':
form = ProcessModelformNew(request.POST or None, template_name= template_name)
Something like this you have to perform

Related

CharField is not rendering in template - Django

I have a date of birth field in my model but why it's not showing up in the template when I render it? The date_of_birth is inside Teacher model. And Do you have any good idea on date_of_birth field? Because right now I'm using charfield for that so I need to convert the DateInput to string so that I can add it into charfield.
here is my models.py
class Teacher(models.Model):
user = models.OneToOneField(CustomUser, on_delete=models.CASCADE, primary_key=True)
date_of_birth = models.CharField(max_length=100)
teacher_type = models.CharField(max_length=50
def __str__(self):
return self.user.email
my forms.py
class TeacherRegisterForm(UserCreationForm):
date_attr = {'class': 'form-control', 'id': 'dateofbirth-register', 'type': 'date'}
date_of_birth = forms.DateField(widget = forms.DateInput(attrs=date_attr))
teacher_type = forms.ChoiceField(label=_('Teacher Type'), choices=type_choice
class Meta(UserCreationForm):
model = CustomUser
fields = ['date_of_birth', 'teacher_type']
def save(self, commit=True):
user = super().save(commit=False)
user.is_teacher = True
user.save()
teacher = Teacher.objects.create(user=user)
teacher.date_of_birth += str(self.cleaned_data.get('date_of_birth'))
teacher.teacher_type += self.cleaned_data.get('teacher_type')
return user
views.py
#login_required
#teacher_required
def teacherInfoView(request):
template_name = "attendance/content/teacher/teacher_info.html"
teacher_info = Teacher.objects.filter(user=request.user)
context = {'teacher_info': teacher_info}
return render(request, template_name, context)
template
{% for info in teacher_info %}
<!-- firstname -->
<div class="row">
<div class="ml-5 mr-auto">
<h5>Name : {{ info.user.first_name }} {{ info.user.last_name }}</h5>
</div>
<div class="ml-5">
<h5>Email : {{ info.user.email }}</h5>
</div>
</div>
<div class="row">
<div class="ml-5">
<h5>Date Of Birth : {{ info.date_of_birth }}</h5>
</div>
<div class="ml-5">
<h5>Gender : {{ info.user.gender }}</h5>
</div>
</div>
{% endfor %}

Django Update unique modelform field

I have created small stock web app.
I created a stock model with unique part_number field. In my update template I send all item information to be displayed. Then I get an error in the part_number field that it is already there.
How can I avoid this validation for that part_number only?
I mean for same part_number suppose validation will not work. But if I modified to another part_number that already exists I get an error that it's being duplicated.
Model:
class Stock(models.Model):
part_number = models.CharField(max_length=30, blank=False, unique=True)
part_name = models.CharField(max_length=70)
quantity = models.IntegerField(blank=False)
location = models.CharField(max_length=3, blank=True)
model = models.CharField(max_length=40, blank=True, null=True, default="")
min_quantity = models.IntegerField(unique=False, blank=True, default=0)
max_quantity = models.IntegerField(unique=False, blank=True, default=0)
class Meta:
ordering = ['part_number']
def clean(self):
self.part_number = self.part_number.upper()
def __str__(self):
return self.part_number
Form.py:
class StockUpdateModelForm(forms.ModelForm):
class Meta:
model = models.Stock
fields = ['part_name', 'quantity', 'location','part_number']
views.py:
def stock_update_form_view(request, part_id):
item = Stock.objects.get(id=part_id)
item_id = Stock.objects.get(id=part_id).pk
form = StockUpdateModelForm({
'part_number' : item.part_number,
'part_name' : item.part_name,
'quantity' : item.quantity,
'location' : item.location
})
if request.method == 'POST':
form = StockUpdateModelForm(request.POST)
if form.is_valid():
s = Stock.objects.get(pk=item_id)
s.part_name = form.cleaned_data['part_name']
s.part_number = form.cleaned_data['part_number']
s.quantity = form.cleaned_data['quantity']
s.location = form.cleaned_data['location']
print("form is valid")
s.save()
return redirect('/stock/')
return render(request, 'stock/stock_update.html', {'form': form, 'pn': item.part_number})
html:
<form class="bg-light shadow" method="POST">
<div style="margin-left:10%; margin-top:30px">
<h4>Part Number : {{ pn }}</h4>
</div>
<hr style="width:100%">
{% csrf_token %}
<div class="row" style="margin-left:30px; margin-top:40px ">
<div class="col-sm-4" style="margin-left:6%">
{{ form.part_name|as_crispy_field }}
</div>
<div class="col-sm-4" style="margin-left:15%">
{{ form.part_number|as_crispy_field }}
</div>
<div class="col-sm-4" style="margin-left:6%">
{{ form.quantity|as_crispy_field }}
</div>
<div class="col-sm-4" style="margin-left:15%">
{{ form.location|as_crispy_field }}
</div>
<div class="col-sm-4" style="height: 100px; margin-top:30px ; margin-left:6%">
<hr style="width:100%">
<input class="btn btn-primary" type="submit" value="Save"
style="width: 150px;">
</div>
</div>
</form>
try this
if request.method == 'POST':
form = StockUpdateModelForm(request.POST, instance=item)
if form.is_valid():
form.save()

Modelset Factory displays a choice fields instead of an input field

Models.py
class Post(models.Model):
title = models.CharField(max_length=100)
conent = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.jpg', upload_to="post_pics")
def __str__(self):
return self.title
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
img = Image.open(self.image.path)
if img.height > 300 or img.width > 300:
output_size = (300, 300)
img.thumbnail(output_size)
img.save(self.image.path)
class Tag(models.Model):
name = models.CharField(max_length=30)
members = models.ManyToManyField(Post, through='PostTag')
def __str__(self):
return self.name
class PostTag(models.Model):
article = models.ForeignKey(Post, on_delete=models.CASCADE)
tag = models.ForeignKey(Tag, on_delete=models.CASCADE)
Forms.py
class PostUpdateForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'conent', 'image']
class TagUpdateForm(forms.ModelForm):
class Meta:
model = PostTag
fields = ['tag']
TagUpdateFormSet = modelformset_factory(PostTag, form=TagUpdateForm)
Views.py
#login_required
def updateView(request, pk):
template_name = 'project/post_update.html'
heading_message = 'Tags'
if request.method == 'GET':
form1 = PostUpdateForm(instance=Post.objects.filter(id=pk).first())
form2 = TagUpdateFormSet(queryset=PostTag.objects.filter(article=Post.objects.filter(id=pk).first()))
elif request.method == 'POST':
form1 = PostUpdateForm(request.POST, request.FILES, instance=Post.objects.filter(id=pk).first())
form2 = TagUpdateFormSet(request.POST, queryset=PostTag.objects.filter(article=Post.objects.filter(id=pk).first()))
if form1.is_valid():
invalid = True
for formz in form2:
if formz.is_valid() == False:
invalid = False
break
if invalid:
postform = form1.save(commit=False)
postform.author = request.user
postform.save()
for forms in form2:
data = forms.cleaned_data.get('tag')
if data:
returnedTag, created1 = Tag.objects.get_or_create(name = data)
link, created2 = PostTag.objects.get_or_create(article = postform, tag = returnedTag)
return HttpResponseRedirect('/forum/post/%s/' %(postform.id))
return render(request, 'project/post_update.html', {'form': form1, 'form2': form2})
template
{% extends "template/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
{% load static %}
<div class="container form-section s-yellow section">
<form method="POST" action="" enctype='multipart/form-data'>
{% csrf_token %}
<fieldset class="form-container">
<legend class="form-top"></legend>
<div class="form1">
{{ form|crispy }}
</div>
<div class="form2 form-group">
{{ form2.management_form }}
{% for formz in form2 %}
<div>
<div class="form-row">
<div class="input-group">
{{formz }}
<div class="">
<button type="button" class="add-form-row">+</button>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Post</button>
</div>
</fieldset>
</form>
</div>
{% endblock content %}
I want to let the user be able to edit all tags in a post, however when i display the tags they show up as choice field that lets the user choose from already existing tags and they can't type a new one.
Is there a way to change the choice field to an input field where the original value is the tag originaly entered.
I tried edditing the 'tag' field to a charfield above the meta tag in the form, but then i was getting an input field with the choice field value (eg 4, 6, 10,) instead of the actual text.
I know the saving part doesnt work, but i need to figure out a way to get the fields dispalyed properly
Btw are there any tutorials for a database structure like this? It's hard to find examples where one table links to 2 others.

What's the best way to post multiple forms of same model in this situation?

I'm trying to post multiple forms of the same model in one submission.
So, I have a model "Task" which has a name, a category and a property field. I have also a model named "Task Check" which has a task and a status. The purpose of task check is to save the status of one task, like "done" or "checked" as can be seen below:
models.py
class Task(models.Model):
name = models.CharField(max_length=100)
category = models.ForeignKey(Categories)
property = models.ManyToManyField(Property)
class TaskCheck(models.Model):
status = models.CharField(choices=STATUS_CHOICES, default='nd', max_length=50)
image = models.ImageField(upload_to='task_check', blank=True, null=True)
notes = models.TextField(max_length=500, blank=True)
task = models.ForeignKey(Task)
property_check = models.ForeignKey(Propertycheck)
class Propertycheck(models.Model):
property = models.ForeignKey(Property, models.DO_NOTHING)
name = models.CharField(max_length=150)
date = models.DateField(default=timezone.now)
next_visit = models.DateField()
staff = models.ForeignKey(User, max_length=25)
notes = models.TextField(max_length=500, blank=True)
As can be seen in the models above, a TaskCheck is related to One PropertyCheck, the purpose of the "PropertyCheck" is to save a set of taskchecks.
Functional Example:
Someone goes to a property to check if everything is ok, he adds a PropertyCheck and then the list of TaskCheck's of every Task related to that property.
My template looks like this:
{% for obj in task %}
{% if obj.category == cat %}
<div class="form-group">
<div class="row">
<div class="col-md-4">
<label for="pname">{{ obj.name }}</label>
{{ task_form.status }}
</div>
<div class="col-md-4">
<label for="pname">Notes</label>
{{ task_form.notes }}
</div>
<div class="col-md-4">
<label for="pname">Image</label>
{{ task_form.image }}
</div>
</div>
</div>
{% endif %}
{% endfor %}
I've reached here, I already have the list of tasks that belong to a specific property:
But now I've no idea about how can I submit all those taskscheck at once. Should it be done with formsets? Is there a proper way to do this? Should I change something on my template?
views.py
def add_propertycheck(request, property_pk):
property_id = property_pk
data = {'property':property_id}
tasks = Task.objects.filter(property=property_pk)
category = tasks.values('category').distinct()
tasks_name = tasks.values('name')
category = tasks.values('category').distinct()
property_reference = Property.objects.get(pk=property_id)
if request.method == 'POST':
taskform = TaskCheckForm(request.POST)
for task in tasks:
if form.is_valid():
checkform = form.save()
return HttpResponseRedirect(reverse('propertycheck:details', args=[pk]))
else:
taskform = TaskCheckForm()
context = {
'task_form':taskform,
'title':"Add Property Check",
'task':tasks,
'reference':property_reference,
'category':category,
}
return render(request, 'propertycheck/add-propertycheck.html', context)

Django form : Doesn't display any form errors

I'm getting an issue with my Django form validation. I would like to display form errors and make all fields required. I don't know why my fields can accept blank while blank is not defined in my model file.
This is my model :
class Customer(models.Model):
email = models.CharField(max_length=150, verbose_name=_('e-mail'), null=False)
first_name = models.CharField(max_length=70, verbose_name=_('first name'), null=False)
last_name = models.CharField(max_length=70, verbose_name=_('last name'), null=False)
country = models.ForeignKey(Country, verbose_name=_('country'))
institution = models.CharField(max_length=255, verbose_name=_('institution'), null=True)
creation_date = models.DateTimeField(auto_now_add=True, verbose_name=_('creation date'), null=False)
modification_date = models.DateTimeField(auto_now=True, verbose_name=_('modification date'), null=False)
class Meta:
verbose_name = _('customer')
verbose_name_plural = _('customer')
def __str__(self):
return f"{self.email}"
This is my form :
class CustomerForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(CustomerForm, self).__init__(*args, **kwargs)
self.fields['country'].empty_label = _('Select a country')
self.fields['country'].queryset = self.fields['country'].queryset.order_by(
'name')
for key in self.fields:
self.fields[key].required = True
class Meta:
model = Customer
fields = ['email', 'first_name', 'last_name', 'country', 'institution']
widgets = {
'email': forms.TextInput(attrs={'placeholder': _('name#example.com')}),
'first_name': forms.TextInput(attrs={'placeholder': _('First Name')}),
'last_name': forms.TextInput(attrs={'placeholder': _('Last Name')}),
'institution': forms.TextInput(attrs={'placeholder': _('Agency, company, academic or other affiliation')}),
}
You can find here my view with Django CBV :
class HomeView(CreateView):
""" Render the home page """
template_name = 'app/index.html'
form_class = CustomerForm
def get_context_data(self, **kwargs):
kwargs['document_list'] = Document.objects.all().order_by('publication__category__name')
return super(HomeView, self).get_context_data(**kwargs)
def post(self, request, *args, **kwargs):
if request.method != 'POST':
return HttpResponseRedirect(self.get_success_url())
form = self.form_class(request.POST)
email = request.POST['email']
country_id = request.POST['country']
country = Country.objects.get(id=country_id)
for checkbox in request.POST.getlist('DocumentChoice'):
document = Document.objects.get(id=checkbox)
token = self.gen_token(email, document.edqm_id)
Download.objects.create(email=email, country=country, pub_id=checkbox, token=token,
expiration_date=now + timedelta(minutes=10))
if not form.is_valid():
print('form invalid')
continue
return HttpResponseRedirect(self.get_success_url())
And finally my template :
{% extends "publication/base_backend.html" %}
{% load staticfiles %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block main %}
<form method="post" id="customerform" novalidate>
{% csrf_token %}
<h3>{% trans 'Your information' %}</h3>
<hr>
<div class="col-sm-12 col-md-12 col-lg-12">
{{ form.email|as_crispy_field:"bootstrap" }}
</div>
<br />
<br />
<br />
<br />
<div class="alert alert-info col-sm-12 col-md-12 col-lg-12" role="alert">
<small>{% trans "The fields below are optional if you have already requested a publication:" %}</small>
</div>
<div class="col-sm-5 col-md-5 col-lg-5">
{{ form.first_name|as_crispy_field:"bootstrap" }}<br>
{{ form.country|as_crispy_field:"bootstrap" }}
</div>
<div class="col-sm-5 col-md-5 col-lg-5 col-sm-offset-2 col-md-offset-2 col-lg-offset-2">
{{ form.last_name|as_crispy_field:"bootstrap" }}<br>
{{ form.institution|as_crispy_field:"bootstrap" }}
</div>
<div class="col-md-12">
<br />
<br />
</div>
<input type="submit" class="btn btn-default" value="{% trans 'Save' %}"/>
{% trans 'Cancel' %}
</form>
Issues :
According to required fields, I don't know why my form doesn't display missing values errors when I want to submit it.
I have to display fields as shown in my template because I have to make bootstrap design.
In order to display form errors, I have to write {{form.email.errors}} for example but nothing appears.
Thank you by advance