I wonder why django modelForm shows input in a column instead of a row like this:
I like all input in my model to be in a row when putting {{ form|crispy}} in the template, as you can see in the template, even if add col-md-3 to resize the input in a row it does not work, I think there is something I need to know about django-forms.
template:
--- Bootstrap-5
<div class="container">
<div class="row justify-content-center">
<div class="col-md-3">
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy}}
<button type="submit" class="btn btn-primary">Create Student</button>
</form>
</div>
</div>
</div>
The Result:
My Forms.py file:
class PrimaryForms(forms.ModelForm):
signature_of_student = JSignatureField(
widget=JSignatureWidget(
jsignature_attrs={'color':'#e0b642', 'height':'200px'}
)
)
signature_of_guardian = JSignatureField(
widget=JSignatureWidget(
jsignature_attrs={'color':'#e0b642', 'height':'200px'}
)
)
date_of_birth = forms.DateField(widget=forms.DateInput(attrs={'type': 'date'}))
class Meta:
model = Primary
fields = ['admission_number', 'profile_picture', 'first_name',
'last_name', 'gender', 'address_of_student', 'class_Of_student',
'comment_of_student', 'year_of_graduation', 'date_of_birth', 'religion', 'mother_name',]
How can I make my input to be in rows?
Related
I have a model with a many to many field (participant field in my Activity model, see below) that I want to edit using createview. However, I can only choose from the already existing entries, not create new ones. It is possible to do that in the admin site so there is a solution but I can't figure it out. I have tried to modify form_valid in views but with no succes. Any ideas how to add or modify a field that has a many to many relation?
views.py:
#response=super(CreateTour,self).form_valid()
#self.object.project=self.form.cleaned_data['participant']
class CreateTour(CreateView):
form_class=CreateTourForm
template_name='artdb/createtour.html'
def get_context_data(self,**kwargs):
context=super(CreateTour,self).get_context_data(**kwargs)
context['formset']=CreateFormset()
return context
def form_valid(self,form):
self.object=form.save(commit=False)
for p in form.cleaned.data['participant']:
ap=Person()
ap.group=self.object
ap.person=ap
ap.save()
return super(self).form_valid(form)
models.py:
class Activity(models.Model):
activity_name=models.CharField(max_length=200,default='no name')
project=models.ForeignKey(Project,on_delete=models.CASCADE,default=1)
participant=models.ManyToManyField(Person)
min_stage_area=models.IntegerField(default='2')
light_requirements=models.CharField(max_length=200,default='no requirements')
sound_engineer=models.CharField(max_length=200,default='not needed')
comment=models.ManyToManyField(Comment)
def __str__(self):
return self.activity_name
class Meta:
ordering = ('activity_name',)
forms.py:
class CreateTourForm(ModelForm):
class Meta:
model=Activity
fields=('activity_name','project','participant')
widgets={'participant':CheckboxSelectMultiple,}
CreateFormset=modelformset_factory(
Activity,
fields=['activity_name','participant'],
extra=1,
widgets={
'date':DateInput(attrs={'type': 'date'}),
}
)
template:
{% extends "artdb/index.html" %}
{% block ct %}
<form method="post">{% csrf_token %}
<div class="input-group">
{% for fr in formset %}
{{fr}}
{% endfor %}
<a>
{{form}}
</a>
<div class="input-group-append">
<button class="btn btn-success add-form-row">+</button>
</div>
</div>
<hr></hr>
<div class="row spacer">
<input type="submit" value="save">
</div>
</form>
{% endblock ct %}
I have a django app where I want to show a table of user entries and users can delete/edit entries from the table by buttons. I used django-tables2 as the library to render the table.
Tables.py
class PatientTable(tables.Table):
FirstName = tables.Column(linkify=("patients:patient_detail", {"pk": tables.A("pk")}))
LastName = tables.Column(linkify=("patients:patient_detail", {"pk": tables.A("pk")}))
Telephone_no = tables.Column(linkify=("patients:patient_detail", {"pk": tables.A("pk")}))
delete = TemplateColumn('<button type ="button" class ="btn btn-danger" data-toggle="modal" data-target="#modalDelete" >Deleta</button>',extra_context={'patient': 'Patient'})
class Meta:
model = Patient
attrs = {'class': 'table table-striped table-hover'}
exclude = ("user", "Notes", "Adress")
template_name = 'django_tables2/bootstrap4.html'
Views.py
def Patients_list(request):
patients = Patient.objects.all()
table = PatientTable(patients.filter(user=request.user))
RequestConfig(request).configure(table)
return render(request, 'patients/patients_list.html',{
'table' : table,
'patients':patients,
})
here in the views I defined the patients in the context to be callable in the template,It's callable but i can't call the patients.pk, it always return a value error.
Template
{% extends 'base.html' %}
{% load render_table from django_tables2 %}
{% block content %}
<div id="content">
{% if user.is_authenticated %}
<h1> Patients list: </h1>
<br>
Add Patient
<br>
<br>
{% render_table table %}
{% else %}
<h2>please login</h2>
{% endif %}
</div>
<div class="modal fade" id="modalDelete" tabindex="-1" role="dialog" aria-labelledby="modalDelete"
aria-hidden="true">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Delete patient!</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>Are you sure you want to delete this patient?</p>
</div>
<div class="modal-footer">
<form method="POST" action="{% url 'patients:patient_delete' pk=patients.pk %}">
{% csrf_token %}
<input class="btn btn-danger" value="Yes" type="submit" >
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
in this template I get this error :
Reverse for 'patient_delete' with keyword arguments '{'pk': ''}' not found. 1 pattern(s) tried: ['patients/delete/(?P<pk>[0-9]+)$']
I tried
Patients.pk
pk
but it didn't work,in the template i tried making a for loop(after deleting the form ofc) to show each patient First name in a paragraph tag and it worked I also tried making a different template having for the delete form and it worked but now i want to make the delete form in a modal callable by the button.
My model:
# Patient model each patient is uniquely identified by his doctor/user
class Patient(models.Model):
FirstName = models.CharField(max_length=264)
LastName = models.CharField(max_length=264)
Adress = models.TextField(blank=True, null=True)
Telephone_no = PhoneNumberField(blank=True, null=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE,related_name='patients')
birth_date = models.DateField()
# Age = models.CharField(max_length=100,blank = True ,null = True)
gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
Notes = models.TextField(blank=True, null=True)
def __str__(self):
return str(self.FirstName) + " " + str(self.LastName)
def get_absolute_url(self):
return reverse('patient_detail', kwargs={"pk": self.pk})
There's another related model to this one has a patient field as a ForiegnKey btw.
I tried changing the view into this as user from recommended but it's the same problem
the new view:
def Patients_list(request):
patients = Patient.objects.filter(user=request.user)
table = PatientTable(patients)
RequestConfig(request).configure(table)
return render(request, 'patients/patients_list.html',{
'table' : table,
'patients':patients,
})
The suggestion was that I couldn't get the pk from Patient.objects.all() and I needed to change it to a form with get but get didn't work so i used filter.
I think if i changed it to a CBV it should work but I don't really know how to make the queryset should i make it with defining it just like the normal CBV.
I've been stuck on this for 10 days now asking on many forums/sites so I really appreciate any help.
The only way to achieve what i wanted is to render the table manually in the template by making a for loop and iterate through all objects.
i tried to return multiple Form Elements with the same name, however i only get the last element not all of them. In my View it works and shows all elements, once i hit submit only the last Element returns (in this case 3 times). Why is that?
forms.py:
class GroupAddForm(forms.ModelForm):
email = forms.EmailField(label='' ,widget=forms.HiddenInput(attrs={'class': 'form-control'}))
page_name = forms.CharField(label='' ,widget=forms.HiddenInput(attrs={'rows': '4', 'class': 'form-control'}))
page_street = forms.CharField(label='' ,widget=forms.HiddenInput(attrs={'rows': '4', 'class': 'form-control'}))
add_button = forms.BooleanField(label='', required=False, widget=forms.CheckboxInput(attrs={'rows': '4', 'class': 'form-control'}))
class Meta:
model = GroupManagement
fields = ['email', 'page_name', 'page_street', 'add_button']
View.py
for items in locationdata:
show_name.append(items[1])
show_street.append(items[2])
name = items[1]
street = items[2]
form = GroupAddForm(request.POST or None, initial={"page_name": name, "page_street": street, "email": email})
forms.append(form)
for item in forms:
if item.is_valid():
email = item.cleaned_data.get("email")
page_name = item.cleaned_data.get("page_name")
page_street = item.cleaned_data.get("page_street")
add_button = item.cleaned_data.get("add_button")
if add_button == true:
//// do stuff
context = {
'names': names,
'street': street,
'group_name_form': group_name_form,
'locationdata': locationdata,
'forms': forms,
}
Template:
<div class="modal-body">
<div class="col-md-12">
<form method="POST" action=""> {% csrf_token %}
{{group_name_form.as_p}}
<div class="col-md-6 pull-left">
{% for items in names %}
<p style="text-align:left;"> {{items.0}} {{items.1}} </p>
{% endfor %}
</div>
<div class="col-md-6">
{% for items in forms %}
{{items.as_p}}
{% endfor %}
</div>
</div>
<input type="submit" class="btn btn-success" value="Gruppe erstellen"></form>
</div>
The correct way to have multiple instances of the same form class is to use formsets.
I created a custom registration form:
class MyRegistrationForm(UserCreationForm):
mobile = models.CharField(max_length=16)
address = models.CharField(max_length=100)
class Meta():
model = CustomUser
fields = ['username', 'password1', 'password2', 'first_name', 'last_name', 'email', 'mobile', 'address']
def clean_mobile(self):
mobile = self.cleaned_data['mobile']
if CustomUser.objects.filter(mobile=mobile).exists():
raise ValidationError('Mobile already exists')
return mobile
def save(self, commit=True):
user = super(MyRegistrationForm, self).save(commit=False)
user.mobile = self.cleaned_data['mobile']
user.address = self.cleaned_data['address']
if commit:
user.save()
return user
And in my template, I don't write just `{{form}}', instead I use my bootstrap template for registration. It looks like:
<form class="form-horizontal" action="{% url 'register' %}" method="post">
{% csrf_token %}
<div class="control-group">
<label class="control-label" for="username1" >Ім'я користувача <sup>*</sup></label>
<div class="controls">
<input type="text" id="username1" placeholder="Нік" name="username">
</div>
</div>
<div class="control-group">
<label class="control-label" for="password_1" >Пароль <sup>*</sup></label>
<div class="controls">
<input type="password" id="password_1" placeholder="Введіть пароль" name="password1">
</div>
</div>
<div class="control-group">
<label class="control-label" for="password_2" >Повторіть пароль <sup>*</sup></label>
<div class="controls">
<input type="password" id="password_2" placeholder="Повторіть пароль" name="password2">
</div>
</div>
But when clean_mobile method is called and raise ValidationError, no errors aren't showed. How to solve this issue? Or maybe I can use in template {{form}} but I need to use bootstrap css?
You need to include {{ form.mobile.errors }} to display errors for your mobile field.
See the working with form templates docs for more information.
You might want to investigate django crispy forms, which makes it easy to render bootstrap forms.
models.py
class Trip(models.Model):
location_name = models.CharField(max_length=60)
trip_date = models.DateField()
trip_rating = models.IntegerField(validators=[MinValueValidator(1),MaxValueValidator(5)])
fishing_vehicle = models.ForeignKey(FishingVehicle)
water_body = models.ForeignKey(WaterBody)
user = models.ForeignKey(User)
def __unicode__(self):
return self.location_name
forms.py
class TripForm(ModelForm):
class Meta:
model = Trip
exclude = ['user']
CHOICES = (('1', 'First',), ('2', 'Second',))
trip_rating = forms.ChoiceField(widget=forms.RadioSelect, choices=CHOICES)
logtrip.html
{% extends "base.html" %}
{% block content %}
<div class="container">
<!-- Example row of columns -->
<div class="row">
<div class="col-md-4">
<form action="/logtrip/" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
</div>
</div>
</div>
{% endblock %}
My form renders without error, but instead of getting a pair of radio buttons for the trip_rating field, a number field is rendered,
<input id="id_trip_rating" name="trip_rating" type="number">
How can I get those radio buttons?
The form field in the modelform is a class level property, and not a Meta property
class TripForm(ModelForm):
CHOICES = (('1', 'First',), ('2', 'Second',))
trip_rating = forms.ChoiceField(widget=forms.RadioSelect, choices=CHOICES)
class Meta:
model = Trip
exclude = ['user']
should do the trick.