Django Forms Set Name Of The Form - html

How can I set the name of the form with model form ?
This is my model form :
class DetayModelForm(forms.ModelForm):
class Meta:
model = Detay
fields = [ 'yazi', 'tip', 'kullanimAdet']
I know how to set name attribute of a field in a form, there are a lot of examples also.
But I really really couldn't find that how can I set the form's own name , not a field in the form, exactly form's own name attribute; in the ModelForm class.
In html side , I will use this attribute : https://www.w3schools.com/tags/att_form_name.asp
I need to use html form name attribute in my template but, I couldn't find how to add this attribute to the form directly in ModelForm class.
I tried to use init in ModelForm class like that :
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.name = 'DetayFormu'
But in html side, still form doesn't have a name attribute.
And also I know , yes I can set this attribute in my template like that :
<form method="post" name="DetayFormu">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-primary">Sign in</button>
</form>
But I really wonder how can I set this attribute in ModelForm class
directly.
How can I do this ?

Just use helper attr to add any new attributes
from crispy_forms.helper import FormHelper
class DetayModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.form_action = 'url'
super(DetayModelForm, self).__init__(*args, **kwargs)
self.helper.attrs = {'name': 'DetayFormu','autocomplete':'off'}
class Meta:
model = Detay
fields = [ 'yazi', 'tip', 'kullanimAdet']

Related

Change crispy forms string representation

Crispy forms use the string representation of objects provided by the str method of the objects' class: I need to change this behaviour (please, help me).
In my crispy form the labels of the choices in a CheckboxSelectMultiple() field populate from the default str method of the objects represented. The set of objects is defined in a list containing ids, with those ids crispy calls the str methods.
Is it possible to write a custom string representation (for instance as a class' #property) and tell crispy to use that instead?
If yes, which point in the pipeline would give the best programmer's practice (models/views/forms/template) ?
this image is just a dummy example for better illustrating the problem
Overriding the default str method provides the desired labelling (as suggested in this post) but is totally unacceptable because of side effects.
models.py
class School(models.Model):
nice_name_for_forms = models.CharField(max_length=100)
#property
def label_from_instance(self):
return '%s' % (self.nice_name_for_forms)
views.py
school_list = School.objects.all().values_list('id', flat=True)
form = MyForm(request.POST, school_list=school_list)
forms.py
class MyForm(forms.ModelForm):
class Meta:
model = MyForm
fields = '__all__'
labels = {'schools' : 'My Schools'}
widgets = {'schools' : forms.CheckboxSelectMultiple()}
def __init__(self, *args, **kwargs):
self.school_list = kwargs.pop('school_list')
super().__init__(*args, **kwargs)
self.fields['schools'].queryset = self.fields['schools'].queryset.filter(id__in=self.school_list).distinct()
self.helper = FormHelper()
self.helper.use_custom_control = False
self.helper.layout = Layout(
Row(CheckboxAllFieldCompact('schools', wrapper_class='col-4 col-md-2'))
checkbox_all_field.html
<!-- crispy/checkbox_all_field.html -->
{% load crispy_forms_field %}
{% load i18n %}
<div id="div_checkbox_all_{{ field.html_name }}" class="no-form-control control-group {{ wrapper_class }}">
<div class="controls" style="max-height:250px;overflow:auto">
<label for="{{ field.name_for_label }}" class="label_title inline">{{ field.label }}</label>
<br />
<label class="block">
<button id="check_all_{{ field.html_name }}" type="button" class="btn btn-default btn-sm" actif="false">{% translate 'Select all' %}</button>
</label>
{% crispy_field field %}
</div>
</div>

Render django's Multiwidget & MutliValueField Textarea using Crispy Forms

I have a TextField intended to store a large amount of text that can be logically split into 10 parts. I thought that it would make sense to create 10 separate Textareas, each for one logical part. Thus, I subclassed MultiWidget and MultiValueField like so:
class MultiWidget(forms.widgets.MultiWidget):
template_name = "custom_content_widget.html"
attrs = {"class": "textarea form-control"}
def __init__(self, attrs=None):
widgets = [Textarea()] * 10
super(MultiWidget, self).__init__(widgets, attrs)
def decompress(self, value):
if value:
return value
return ["", "", "", "", "", "", "", "", "", ""]
class ContentField(MultiValueField):
widget = MultiWidget
def __init__(self, *args, **kwargs):
# Define one message for all fields.
error_messages = {
'required': 'This field is required.',
}
# Or define a different message for each field.
fields = [CharField()] * 10
super(ContentField, self).__init__(
error_messages=error_messages, fields=fields, require_all_fields=True, *args, **kwargs)
# self.helper = FormHelper()
# self.helper.layout = Layout(
#
# )
def compress(self, data_list):
return " ".join(data_list)
with the custom_content_widget.html being just
{% for subwidget in widget.subwidgets %}
{% with widget=subwidget %}
{% include widget.template_name %}
{% endwith %}
{% endfor %}
Simple model and form in which I'd like to use this multiwidget
class Opinion(models.Model):
content = models.TextField()
class OpinionForm(forms.ModelForm):
content = ContentField()
class Meta:
model = Opinion
fields = ('__all__')
The problem is that when I use content in my form's HMTL as {{ form.content | as_crispy_field }} it renders pretty ugly
and I'd like all of the Textareas to be rendered one under the other. The main issue here is that textarea is rendered as
<textarea name="content_0" cols="40" rows="10" class="textarea" required id="id_content_0">
</textarea>
while "normal" TextField is rendered as
<textarea name="content" cols="40" rows="10" class="textarea form-control" required id="id_content">
</textarea>
and I have no clue how could I force the class of the widget to be textarea form-control instead of textarea. Initially, I found this question and also this blog but all they do is just to properly group widgets into rows and columns. Is there anything I am missing here?
The key was to pass attributes dict with "class": "textarea form-control" to the MultiWidget constructor as follows
class ContentField(MultiValueField):
widget = MultiWidget({"class": "textarea form-control"})
def __init__(self, *args, **kwargs):
# Define one message for all fields.
error_messages = {
'required': 'This field is required.',
}
# Or define a different message for each field.
fields = [CharField()] * 10
super(ContentField, self).__init__(
error_messages=error_messages, fields=fields, require_all_fields=True, *args, **kwargs)
def compress(self, data_list):
return " ".join(data_list)

Invalid form when uploading file in Django

I need to upload file on a Django page, however, after following the official tutorial, I was not able to upload it, it always gives the error "invalid form", and when I tried to print out the error msg of the form, it says "This field is required".
One thing notable is: I have 2 forms on one page, one is this upload form and the other one is for filling out information. Not sure if this is the root cause.
I have tried all solutions provided on the Internet.
Template file:
<form id="uploadForm" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="file" value="upload" name="sourcefile">
<button type="submit">Upload</button>
</form>
Forms.py:
from django import forms
from .models import SourceFile
class UploadFileForm(forms.ModelForm):
class Meta:
model = SourceFile
fields = ('file', 'title')
Models.py:
from django.db import models
# Create your models here.
class SourceFile(models.Model):
title = models.CharField(max_length=255, blank=True)
file = models.FileField(upload_to="media/")
Views.py
def model_form_upload(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
instance = SourceFile(file_field=request.FILES['file'])
instance.save()
return JsonResponse({'error': False, 'message': 'Uploaded Successfully!'})
else:
print("Invalid form")
# return JsonResponse({'error': True, 'errors': form.errors})
else:
form = UploadFileForm()
return render(request, 'source_validation.html', {'form': form})
Your template is wrong. Either use {{ form.as_p }} which should display a file input field because file is a field in your form. (so remove the <input type="file" ...>)
Or don't use it and manually add the <input> fields, but then you must use the correct names. Your form expects a "file" parameter, not a "sourcefile" parameter:
<input type="file" name="file">
Also, you're overcomplicating things in your view (even though your current code will work if you fix your template):
if form.is_valid():
form.save() # this will save your model
return redirect(...)

django form to apply for designed html elements

I hve this html file:
<form method='POST'>
{% csrf_token %}
<input name='foo'/>
<button type="submit">submit</button>
</form>
Now, imagine this form has css atributes behind, I just want a form which would configure some inputs. For an example. The field is required, the min length is 10 chars, etc etc.
How could i approach that with Django forms?
is the something like:
from django import forms
class inputform(forms.Form):
input_line = forms.CharField(max_length=20, min_length=10, name='foo')
how would i apply that to vies.py and how to get errors out to html?
Would appreciate your reply.
you can try this.
class inputForm(forms.Form):
input_line = forms.CharField(max_length=30, widget=forms.TextInput(attrs={'class' : 'input-field form-control'}))
def clean(self, *args, **kwargs):
cleaned_data = super(inputForm, self).clean()
my_input = self.cleaned_data.get("input_line")
if not my_input:
raise forms.ValidationError('This field is required')
if len(my_input) < 10:
raise forms.ValidationError('the min length is 10 character')
return cleaned_data
the clean() method is used for validating input from form.

Django 'ManagementForm data is missing or has been tampered with' when saving modelForms with foreign key link

I am rather new to Django so this may be an easy question. I have 2 modelForms where there is a ForeignKey to another. My main goal is to save Indicators with a link to Disease (FK), such that for a particular disease, you can have multiple indicators.
With the code below, I get an error when I hit submit that says 'ManagementForm data is missing or has been tampered with'. Also, the code in views.py does not seem to be validating at the 3rd 'if' statement where there is a return HttpResponseRedirect. However, when I check my database, the values from the form have been written. Any ideas on why the error has been raised? and how to fix it?
My code is below:
models.py
#Table for Disease
class Disease(models.Model):
disease = models.CharField(max_length=300)
#Tables for Indicators
class Indicator(models.Model):
relevantdisease = models.ForeignKey(Disease)
indicator = models.CharField(max_length=300)
forms.py
class DiseaseForm(forms.ModelForm):
class Meta:
model = Disease
class IndicatorForm(forms.ModelForm):
class Meta:
model = Indicator
DiseaseFormSet = inlineformset_factory(Disease,
Indicator,
can_delete=False,
form=DiseaseForm)
views.py
def drui(request):
if request.method == "POST":
indicatorForm = IndicatorForm(request.POST)
if indicatorForm.is_valid():
new_indicator = indicatorForm.save()
diseaseInlineFormSet = DiseaseFormSet(request.POST, request.FILES, instance=new_indicator)
if diseaseInlineFormSet.is_valid():
diseaseInlineFormset.save()
return HttpResponseRedirect('some_url.html')
else:
indicatorForm = IndicatorForm()
diseaseInlineFormSet = DiseaseFormSet()
return render_to_response("drui.html", {'indicatorForm': indicatorForm, 'diseaseInlineFormSet': diseaseInlineFormSet},context_instance=RequestContext(request))
template.html
<form class="disease_form" action="{% url drui %}" method="post">{% csrf_token %}
{{ indicatorForm.as_table }}
<input type="submit" name="submit" value="Submit" class="button">
</form>
You have neither diseaseFormSet nor diseaseFormSet's management form in your template, yet you try to instantiate the formset. Formsets require the hidden management form which tells django how many forms are in the set.
Insert this into your HTML
{{ diseaseFormSet.as_table }}
{{ diseaseFormSet.management_form }}