Here's my form i am trying to user to pass two char fields and two coordinates so they can be turned into objects. I just figured out the validation on the char fields, but now the decimal fields wont work. Any suggestions?
from django import forms
class SubmitForm(forms.Form):
title = forms.CharField(max_length=100)
story = forms.CharField(max_length=3000)
lat = forms.DecimalField(max_digits=25, decimal_places=20)
lng = forms.DecimalField(max_digits=25, decimal_places=20)
def clean_title(self):
if len(self.cleaned_data['title']) < 4:
raise forms.ValidationError("Enter your full title")
# Always return the cleaned data
return self.cleaned_data['title']
def clean_story(self):
if len(self.cleaned_data['story']) < 4:
raise forms.ValidationError("Enter your full story")
# Always return the cleaned data
return self.cleaned_data['story']
def clean_lng(self):
if self.cleaned_data['lng'] == 0.0:
raise forms.ValidationError("Enter your full story")
return self.cleaned_data['lng']
def clean_lat(self):
if self.cleaned_data['lat'] == 0.0:
raise forms.ValidationError("Enter your full story")
# Always return the cleaned data
return self.cleaned_data['lat']
def clean(self):
cleaned_data = self.cleaned_data
return cleaned_data
Here's my view
def test(request):
ctxt = {}
if request.method == 'POST':
form = SubmitForm(request.POST) # A form bound to the POST data
if form.is_valid():
lat1 = form.cleaned_data['lat']
lng1 = form.cleaned_data['lng']
# title1 = form.cleaned_data['title']
titlepost = form.cleaned_data['title']
story1 = form.cleaned_data['story']
ctxt = {'titlehere':titlepost}
catid = "test1234"
cat = Category(category=catid)
cat.full_clean()
cat.save()
marker = Marker(lat=lat1, lng=lng1,category=cat, title=titlepost, story=story1)
marker.full_clean()
marker.save()
return render_to_response('home.html', ctxt, context_instance=RequestContext(request))
else:
return render_to_response('test.html', ctxt, context_instance=RequestContext(request))
else:
now = datetime.datetime.now()
form = SubmitForm()
latest_marks = Marker.objects.all().order_by('-submitted')[0:10]
ctxt = {
'marks':latest_marks,
'now':now.date(),
'form': form,
}
return render_to_response('test.html', ctxt, context_instance=RequestContext(request))
For some reason each time i send the form I get this error message
Not really sure what going on. Still pretty new to Django. Any help would be appreciated.
Edit: add in colons I was missing. Error still consists
You're missing some colons after your if statements in the clean methods of your form.
Did you consider using Modelforms ?
You can simplify your code just by using a modelform for Marker model (less code duplication, less code in general to create the model ...)
FYI:
You can send the min_length to CharField and get the len() validation for free :)
class SubmitForm(forms.Form):
title = forms.CharField(max_length=100, min_length=4)
For some reason each time i send the form I get this error message
I can't see the error!
But I tried this and it works ok.
import math
class MyForm(forms.Form):
title = forms.CharField(max_length=100, min_length=4)
story = forms.CharField(max_length=3000, min_length=4)
lat = forms.DecimalField(max_digits=25, decimal_places=20)
lng = forms.DecimalField(max_digits=25, decimal_places=20)
def clean_lat(self):
lat = self.cleaned_data['lat']
if math.ceil(float(lat)) <= 0:
raise forms.ValidationError("Enter your full story")
return self.cleaned_data['lat']
def clean_lng(self):
lng = self.cleaned_data['lng']
if math.ceil(float(lng)) <= 0:
raise forms.ValidationError("Enter your full story")
return self.cleaned_data['lng']
Related
I have a form with counterparty, object and sections i connected them to each other with django-forms-dynamic package but object not connected to sections
Counterparty connected to object form but sections are not connected to object how can i fix that?
I guess that im wrong with 2 functions in forms.py: section_choices and initial_sections and they`re not connected to objects but dont know how to fix that
forms.py
class WorkLogForm(DynamicFormMixin, forms.ModelForm):
def object_choices(form):
contractor_counter = form['contractor_counter'].value()
object_query = ObjectList.objects.filter(contractor_guid__in=[contractor_counter])
return object_query
def initial_object(form):
contractor_counter = form['contractor_counter'].value()
object_query = ObjectList.objects.filter(contractor_guid__in=[contractor_counter])
return object_query.first()
def section_choices(form):
contractor_object = form['contractor_object'].value()
section_query = SectionList.objects.filter(object=contractor_object)
return section_query
def initial_sections(form):
contractor_object = form['contractor_object'].value()
section_query = SectionList.objects.filter(object=contractor_object)
return section_query.first()
contractor_counter = forms.ModelChoiceField(
label='Контрагент',
queryset=CounterParty.objects.none(),
initial=CounterParty.objects.first(),
empty_label='',
)
contractor_object = DynamicField(
forms.ModelChoiceField,
label='Объект',
queryset=object_choices,
initial=initial_object,
)
contractor_section = DynamicField(
forms.ModelMultipleChoiceField,
label='Раздел',
queryset=section_choices,
initial=initial_sections,
)
views.py
#login_required
def create_work_log(request):
if request.method == 'POST':
form = WorkLogForm(request.POST, user=request.user)
if form.is_valid():
work_log = form.save(commit=False)
work_log.author = request.user
work_log = form.save()
messages.success(request, 'Данные занесены успешно', {'work_log': work_log})
return redirect('create_worklog')
else:
messages.error(request, 'Ошибка валидации')
return redirect('create_worklog')
form = WorkLogForm(user=request.user, initial=initial)
return render(request, 'contractor/create_work_log.html', {'form': form})
def contractor_object(request):
form = WorkLogForm(request.GET, user=request.user)
return HttpResponse(form['contractor_object'])
def contractor_section(request):
form = WorkLogForm(request.GET, user=request.user)
return HttpResponse(form['contractor_section'])
This may not be an answer you want but I use HTMX for these things. Here is a link to their example for this.
https://htmx.org/examples/value-select/
There is also a package plugin called Django-htmx.
You may need to learn HTMX but it is a mature technology, rather simple and reliable. I am unfamiliar with Django-forms-dynamic
Peace be upon all, I just started Django last month. I needed help running concurrency tests in Django, so what I've done is tried to write code that will prevent issues that arise due to lack of concurrency but what I don't know is how to verify and test the code to see that it meets my expectations. What I want is to send multiple requests at the same time to see if the code works as expected.
The target function in views.py
def buy_animal(request):
context = {}
if request.method == 'POST':
form = buys_animal(request.POST)
if form.is_valid() == True or form.is_valid() == False:
#return HttpResponse('asdasd')
nm = request.POST['an_name']
b = Animal.objects.filter(an_name = nm)
#return HttpResponse("yo ")
#nm = request.POST['an_name']
qt = int(request.POST['qty'])
if b.count() <= 0:
return HttpResponse(str(b.count()) + " Sorry we're out of animals")
else:
try:
with transaction.atomic():
b.select_for_update()
b = b[0]
#b.an_name = 'asd'
#b.save()
with transaction.atomic():
Quality.objects.filter( animal = Animal.objects.filter(an_name = 'ringneck')[0] ).select_for_update()
c = Quality.objects.filter( animal = Animal.objects.filter(an_name = 'ringneck')[0] )[0]
c.rating = 'niece'
c.save()
except:
return HttpResponse('Database Error')
if b.qty - qt < 0:
return HttpResponse("Sorry we don't have enough animals")
else:
b.qty = b.qty - qt
b.save()
a = Buy_animal( an_name = nm, qty = qt,
buyer = MyUser.objects.filter(username = request.user.username)[0] )
a.save()
return HttpResponse('animal bought')
else :
form = buys_animal()
context = {}
context = {'form' : form}
return render(request, "buy_animal_form.html", context)
else :
form = buys_animal()
context = {}
context = {'form' : form}
return render(request, "buy_animal_form.html", context)
My models.py code can be found in the below repository
https://bitbucket.org/mab_786/django_models_code/src/master/models.py
`
Kindly ignore any stupid errors on my part as I just started with django.
Thanks in advance. I would really appreciate if someone could share the tests.py code to test such a situation. I didn't write this code as part of any project but to clear up my concepts
In my project, the user is entering data in a settings page of the application and it should update the database with the user's settings preference. I read this answer by Alasdair and how using the __init__() will allow to access the user's details. I was wondering if it's possible to return data from __init__() so I can validate the entered data before calling the save() function in the view? This is what I tried (and did not work). I am open to going about this in a better approach so I appreciate all your suggestions!
**EDIT: ** I am deciding on moving the validation of the data entered by the user in the forms file because when I wrote it in my views, I ended up getting 5 if statements (nested). IMO, and given the situation of this application, moving it to the forms seems to be a cleaner approach. I also considered using the clean_['field'] but I need the side variable from the __init__() function to do that and I am not sure how to extract that value.
Forms.py
class t_max_form(forms.ModelForm):
side = None
def __init__(self, *args, **kwargs):
side = kwargs.pop('side', None)
super(t_max_form, self).__init__(*args,**kwargs)
if side == "ms":
self.fields['hs_max_sessions'].widget.attrs.update({'class':'form-control', 'readonly':True})
self.fields['ms_max_sessions'].widget.attrs.update({'class':'form-control mb-3'})
elif side == "hs":
self.fields['hs_max_sessions'].widget.attrs.update({'class':'form-control'})
self.fields['ms_max_sessions'].widget.attrs.update({'class':'form-control', 'readonly':True})
else:
self.fields['hs_max_sessions'].widget.attrs.update({'class':'form-control'})
self.fields['ms_max_sessions'].widget.attrs.update({'class':'form-control'})
#Trying to validate the data here
valid_session_count = settings.objects.first()
if(side == "ms"):
input_sessions = self.fields['ms_max_sessions'].widget.attrs['readonly']
if(input_sessions > valid_session_count.max_sessions):
self.add_error("ms_max_sessions", "You have entered more than the limit set by the TC. Try again")
elif(side == "hs"):
input_sessions = self.cleaned_data['hs_max_sessions']
if(input_sessions > valid_session_count.max_sessions):
self.add_error("hs_max_sessions", "You have entered more than the limit set by the TC. Try again")
else:
input_sessions = self.cleaned_data['ms_max_sessions'] + self.cleaned_data['hs_max_sessions']
if(input_sessions > valid_session_count.max_sessions):
self.add_error("hs_max_sessions", "You have entered more than the limit set by the TC. Try again")
return input_sessions
And this is what I was trying in my views
views.py
def t_time_slots(request):
name = request.user.username
t = t_info.objects.get(student__user__username = name)
timeSlots = tutor_time_slot.objects.filter(tutor = tutor).order_by('time')
side = decide_side(request.user)
if request.method == 'POST':
form = t_time_slot_form(request.POST)
if form.is_valid():
if check_unique_time_slot(request.user, form.cleaned_data['day'], form.cleaned_data['time']):
timeSlots = form.save(commit=False)
timeSlots.t = t
timeSlots.save()
messages.success(request, "Added Successfully")
return redirect('TTimeSlot')
else:
print("Overlap")
messages.error(request, "The time slot overlaps with a Current one. Please Change the time and try again.")
return redirect('TTimeSlot')
else:
form = t_time_slot_form()
context = {'timeSlots': timeSlots, 'form': form, 'side':side}
return render(request, 't/t_time_slot.html', context)
Set self.side in the __init__ method, then you can access it in the clean() or clean_<field> methods.
I would avoid putting validation code in the __init__ method.
class MyForm(forms.Form):
my_field = forms.CharField()
def __init__(self, *args, **kwargs):
self.side = kwargs.pop('side', None)
super(t_max_form, self).__init__(*args,**kwargs)
...
def clean_my_field(self):
my_field = self.cleaned_data['my_field']
# Use self.side to validate data
if my_field = self.side:
raise forms.ValidationError("Invalid")
return my_field
I have a Django form that lets users choose a tag from multiple tag options. The problem I am facing is that even when the tag list gets updated, the model form does not get the updated tag list from database. As a result, new tags do not appear in options.
Here is my code in forms.py:
class EnglishTagForm(forms.Form):
tag_choices = [(x.tagName, x.tagName.upper()) for x in ClassTag.objects.filter(
agentId=Agent.objects.get(name='English Chowdhury'))]
tag = forms.CharField(widget=forms.Select(choices=tag_choices,
attrs={'class':'form-control'}))
def __init__(self, *args, **kwargs):
super(EnglishTagForm, self).__init__(*args, **kwargs)
self.fields['tag'].choices = [(x.tagName,
x.tagName.upper()) for x in ClassTag.objects.filter(
agentId=Agent.objects.get(name='English Chowdhury'))]
This form is being instantiated in view. My question is what changes should I do so that tag_choices gets updated from database on every instantiation.
How the above form is used in views.py:
```
def complaintDetail(request, complaint_id):
complaint = Complaints.objects.filter(pk=complaint_id).first()
context = {}
if request.method == 'POST':
agent = Agent.objects.get(name="English Chowdhury")
if "SubmitTag" in request.POST:
englishForm = EnglishTagForm(request.POST)
if englishForm.is_valid:
// Complaint Delete Logic
return redirect('chatbot:modComplaints')
else:
englishForm = EnglishTagForm()
context['eForm'] = englishForm
elif "SubmitBundle" in request.POST:
newTagForm = NewTagForm(request.POST)
if newTagForm.is_valid():
// Complaint Delete Logic
complaint.delete()
return redirect('chatbot:modComplaints')
else:
newTagForm = NewTagForm()
context['newForm'] = newTagForm
else:
englishForm = EnglishTagForm()
context['eForm'] = englishForm
newTagForm = NewTagForm()
context['newForm'] = newTagForm
context['complaint'] = complaint
return render(request, 'chatbot/complaintDetail.html', context)
```
Edit: (For future reference)
I decided to modify the tag attribute and convert CharField to ModelChoiceField, which seems to fix the issue.
Updated Class:
class EnglishTagForm(forms.Form):
tag = forms.ModelChoiceField(queryset=ClassTag.objects.filter(
agentId=Agent.objects.get(name='English Chowdhury')),
empty_label=None, widget=forms.Select(
attrs={'class':'form-control'}))
Please remove the list comprehension from Line 2. So that,
tag_choices = [(x.tagName, x.tagName.upper()) for x in ClassTag.objects.filter(
agentId=Agent.objects.get(name='English Chowdhury'))]
becomes
tag_choices = []
G'day there. I've currently got a bit of an annoyance more than anything. The code below works fully, as expected. Basically it's a ModelForm that dynamically bases it's model on a string received in the url, or based on the class of an instance if that's provided.
My question is whether it's possible to abstract this out into another module, forms.py, by passing the model_name variable. I can pass model_name to the form Class no problems, but I can't figure out how to pass it to Meta after that. Is there any easy way to do this? If not this'll do, but it would make my view code heaps neater.
#user_passes_test(lambda u: u.is_staff, login_url="%slogin/" % NINJA_ADMIN_URL_PREFIX)
def content_form(request, model_name=None, edit=False, call_name=''):
if edit:
content = Content.objects.get(call_name=call_name)
model_name = content.fields.__class__.__name__
class ContentForm(forms.ModelForm):
parent = ModelTextField(queryset=Content.objects.all(), widget=JQueryAutocomplete(
source_url='%sjson/call_names.json' % NINJA_ADMIN_URL_PREFIX, jquery_opts = {'minLength': 2},
override_label='item.fields.call_name', override_value='item.fields.call_name'),
required=False)
class Meta():
model = get_ninja_type(model_name)
widgets = {
'ninja_type': forms.widgets.HiddenInput(),
}
def clean_parent(self):
call_name = self.cleaned_data['parent']
if call_name:
try:
parent = Content.objects.get(call_name=call_name)
except Content.DoesNotExist:
raise forms.ValidationError("The call name '%s' doesn't exist. Choose another parent." % call_name)
return parent
else:
return None
if request.method == 'POST':
if edit:
form = ContentForm(request.POST, instance=content.fields)
else:
form = ContentForm(request.POST)
if form.is_valid():
content = form.save()
messages.success(request, "Your new content has been saved.")
return HttpResponseRedirect('%scontent/' % NINJA_ADMIN_URL_PREFIX)
else:
if edit:
form = ContentForm(instance=content.fields)
else:
form = ContentForm(initial={'ninja_type': model_name.lower(),
'author': request.user})
if edit:
page_title = 'Edit %s' % model_name
else:
page_title = 'Create New %s' % model_name
return render(request, 'ninja/admin/content_form.html', {
'form': form,
'ninja_type': model_name,
'page_title': page_title,
'edit': edit,
'meta_field_names': NINJA_META_FIELD_NAMES,
})
The answer was pretty obvious when I thought about it. A function returning a class works fine. This is what's left at the start of views.py. I'm thinking this is likely the best way to do this, or at least the most concise.
#user_passes_test(lambda u: u.is_staff, login_url="%slogin/" % NINJA_ADMIN_URL_PREFIX)
def content_form(request, model_name=None, edit=False, call_name=''):
if edit:
content = Content.objects.get(call_name=call_name)
model_name = content.fields.__class__.__name__
ContentForm = get_content_form(model_name)
if request.method == 'POST':
if edit:
form = ContentForm(request.POST, instance=content.fields)
else:
This is the forms.py entry.
def get_content_form(model_name):
class DynamicContentForm(forms.ModelForm):
parent = ModelTextField(queryset=Content.objects.all(), widget=JQueryAutocomplete(
source_url='%sjson/call_names.json' % NINJA_ADMIN_URL_PREFIX, jquery_opts = {'minLength': 2},
override_label='item.fields.call_name', override_value='item.fields.call_name'),
required=False)
class Meta():
model = get_ninja_type(model_name)
widgets = {
'ninja_type': forms.widgets.HiddenInput(),
}
def clean_parent(self):
call_name = self.cleaned_data['parent']
if call_name:
try:
parent = Content.objects.get(call_name=call_name)
except Content.DoesNotExist:
raise forms.ValidationError("The call name '%s' doesn't exist. Choose another parent." % call_name)
return parent
else:
return None
return DynamicContentForm