I'm using Django Model Form. Can anyone help me validate those fields to get field error using clean()?
The Name field cannot be repeated in the same office, only in a different one.
form.py
class CreateSalesRepForm(forms.ModelForm):
class Meta:
model = CreateSalesRep
fields = ['name', 'office']
widgets = {
'office': forms.Select(attrs={'class': 'form-control', 'placeholder': 'Enter Office'}),
'name': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Enter Name'})
}
UPDATED (form.py) --- Here is the solution, you can use this codes to validate both insert and update form.
def clean(self):
cleaned_data = super().clean()
office = cleaned_data.get("office")
name = cleaned_data.get("name")
duplicates = CreateSalesRep.objects.filter(office=office, name=name)
if (self.instance.pk and None):
duplicates = duplicates.filter(pk=self.instance.pk)
if duplicates.exists():
msg = "Name already exist in office selected"
self.add_error('name', msg)
self.add_error('office', msg)
view.py
def create_salesrep(request):
if request.method == "POST":
form = CreateSalesRepForm(request.POST or None)
if form.is_valid():
form.save()
messages.success(request, 'Successfully Saved!', 'alert-success')
return redirect('sales_rep')
else:
return render(request, 'salesrep/create_salesrep.html', {'form':form})
else:
form = CreateSalesRepForm()
context = {'form':form}
return render(request, 'salesrep/create_salesrep.html', context)
def update_salesrep(request, pk):
srep = CreateSalesRep.objects.get(id=pk)
form = CreateSalesRepForm(instance=srep)
if request.method == "POST":
form = CreateSalesRepForm(request.POST or None, instance=srep)
if form.is_valid():
form.save()
messages.success(request, 'Successfully Updated!', 'alert-success')
return redirect('sales_rep')
else:
return render(request, 'salesrep/update_salesrep.html', {'form':form})
else:
form = CreateSalesRepForm(instance=srep)
return render(request, 'salesrep/update_salesrep.html', {'form':form})
You can validate in the forms:
class CreateSalesRepForm(forms.ModelForm):
class Meta:
model = CreateSalesRep
fields = ['name', 'office']
def clean(self):
cleaned_data = super().clean()
office= cleaned_data.get("office")
name = cleaned_data.get("name")
duplicates = CreateSalesRep.objects.filter(office=office, name=name)
if self.instance.pk:
duplicates = duplicates.filter(pk=self.instance.pk)
if duplicates.exists():
raise forms.ValidationError('Name already in office')
That being said, you could enforce this in the model/db level as well by adding the following to your CreateSalesRep model:
class CreateSalesRep(models.Model):
...
class Meta:
unique_together = ['office', 'name']
You can try following inside your model class
class Meta:
unique_together = [('office', 'name')]
Related
I want to Update some value of a Book instance in Django from. I have put clean_field() methods in forms.py. So, everytime I update the value in a form it validates the clean_field and raises a validationError for those two fields. I want to bypass that while I update the object's some parameter like bookPrice or publicationDate. so, I can update that value without getting an error on existing fields. I have put clean_field() for bookname,bookisbn.
views.py
def updateBook(request, key_id):
book = Book.objects.get(bookIsbn__exact=key_id)
# date format 2/21/2020
print(request.method)
if request.method == 'POST':
form = BookUploadForm(request.POST, request.FILES, instance=book)
if form.is_valid():
form.save()
return redirect('bookList')
else:
print(form.errors.as_data())
form = BookUploadForm(request.POST or None, request.FILES or None, instance=book)
template = 'storeApp-Templates/bookUpdate.html'
context = {'book': book, 'form': form}
return render(request, template, context)
form.py
class BookUploadForm(forms.ModelForm):
class Meta:
model = Book
fields = "__all__"
widgets = {
'bookName': forms.TextInput(attrs={'class': 'form-controls'}),
'bookPrice': forms.TextInput(attrs={'class': 'form-controls'}),
'bookAuthor': forms.TextInput(attrs={'class': 'form-controls'}),
'bookIsbn': forms.TextInput(attrs={'class': 'form-controls'}),
'bookPublicationDate': forms.DateInput(attrs={'class': 'form-controls'}),
}
bookPublicationDate = forms.DateField(widget=AdminDateWidget())
# this methods will generate error for book update as well as new book Upload
def clean_bookName(self, *args, **kwargs):
bookname = self.cleaned_data.get('bookName')
qs = Book.objects.filter(bookName__exact=bookname)
if qs.exists():
raise forms.ValidationError("This BookName has already been used.")
return bookname
def clean_bookIsbn(self, *args, **kwargs):
bookisbn = self.cleaned_data.get('bookIsbn')
qs = Book.objects.filter(bookIsbn__exact=bookisbn)
if qs.exists():
raise forms.ValidationError("This ISBN has already been used. Please Use a new ISBN.")
if len(bookisbn) != 11 and len(bookisbn) != 13:
raise forms.ValidationError("ISBN length has to be 11 or 13.")
return bookisbn
So, because of this clean_field() i cant update any value in a book instance any object I try to update it raises a validationError of This BookName has already been used && This ISBN has already been used. Please Use a new ISBN. Because of that clean_field() validation in form.py.
I have this form:
class addMeal(forms.Form):
name = forms.CharField(
max_length=40,
widget=forms.TextInput(attrs={'class':'form-control','placeholder':'نام وعده'})
)
foods = forms.ModelMultipleChoiceField(
queryset=Food.objects.none(),
widget=forms.SelectMultiple(attrs={'class':'form-control'})
)
def save(self,request):
data = self.cleaned_data
meal = Meals(name=data['name'],user=request.user,foods=data['foods'])
meal.save()
def __init__(self, user=None,*args, **kwargs, ):
super().__init__(*args, **kwargs)
if user is not None:
self.fields['foods'].queryset = Food.objects.filter(user=user)
class Meta:
model = Meals
and this view:
#login_required
def addmeal(request):
if request.method == 'POST':
form = addMeal(request.POST)
if form.is_valid():
form.save(request)
return redirect('food:index')
else:
form = addMeal(user=request.user)
return render(request,'addmeal.html',{'form':form})
when i fill out form and press submit django give me error(Field 'id' expected a number but got <QueryDict: {'csrfmiddlewaretoken': ['C2B8y3kLCa5IQ0S5Mvk7Tw0NTU4pNlYicppWlsIL1LCrcc8AuCQzjJkqWNUot4z6'], 'name': ['شام'], 'foods': ['1']}>.).
what should i do to fix it?
Since user is the first parameter, you pass the data as second, so:
#login_required
def addmeal(request):
if request.method == 'POST':
form = addMeal(user=request.user, data=request.POST)
if form.is_valid():
form.save(request)
return redirect('food:index')
else:
form = addMeal(user=request.user)
return render(request,'addmeal.html',{'form':form})
I have a form in my application which has a hidden form field, the value of which I want to set in my corresponding view after submitting the form.
forms.py
class EvangelizedForm(forms.ModelForm):
first_name = forms.CharField(help_text="First Name")
last_name = forms.CharField(help_text="Last Name")
email = forms.CharField(help_text="Email ID")
mobile_no = forms.CharField(help_text="Mobile number")
twitter_url = forms.CharField(help_text="Twitter URL")
twitter_followers = forms.CharField(widget = forms.HiddenInput()) #Hidden form field
class Meta:
model = Evangelized
fields = ('first_name','last_name', 'twitter_url', 'email', 'mobile_no')
models.py
class Evangelized(models.Model):
first_name = models.CharField(max_length=128)
last_name = models.CharField(max_length=128)
email = models.EmailField()
mobile_no = models.CharField(unique=True, max_length = 10, validators=[RegexValidator(regex='^\w{10}$', message='Mobile number should be strictly of 10 digits.')])
twitter_url = models.CharField(unique=True, max_length=128)
twitter_followers = models.CharField(max_length = 128)
views.py
def fillform(request):
follower_count = '250'
if request.method == 'POST':
form = EvangelizedForm(request.POST)
if form.is_valid():
form.fields['twitter_followers'] = follower_count
form.save(commit=True)
return index(request)
else:
form.errors
else:
#form = EvangelizedForm()
if request.user.is_authenticated():
form = EvangelizedForm(initial={'first_name': request.user.first_name,
'twitter_url': 'https://twitter.com/' + request.user.username,
'last_name': request.user.last_name})
else:
form = EvangelizedForm()
context = RequestContext(request,
{'request': request,
'user': request.user, 'form':form})
#return render(request, 'rango/fillform.html', {'form': form, 'context_instance':context})
return render_to_response('rango/fillform.html',
context_instance=context)
Basically, I'm trying to set the value of twitter_followers (which is a hidden form field in forms.py) in my index view, by:
follower_count = '250'
..
..
form.fields['twitter_followers'] = follower_count
By doing this, I'm expecting the value of 'twitter_followers' in the database after submitting the form to be '250'. However, this approach doesn't seem to be working.
What's the right way to set values to certain attributes in the database manually using views?
You need to set it on the model instance, which is the result of form.save. That's the main reason for the commit argument in the first place.
if form.is_valid()
obj = form.save(commit=True)
obj.twitter_follower = follower_count
obj.save()
You can override the save method of the form, with something like this:
def save(self, *args, **kwargs)
twitter_followers = kwargs.pop('twitter_followers', 0)
self.instance.twitter_followers = twitter_followers
super(Evangelized, self).save(args, kwargs)
And then in the view just have to call in this way:
form.save(twitter_followers=250)
I have a from created which is generated by a model. I can save the form, but the form data is not inserted into the table. The insert occurs, but with blank data. Any help would be greatly appreciated.
models.py
class HelpDefinition(models.Model):
org = models.IntegerField(default=0)
help_type = models.CharField(max_length=255)
help_content = models.TextField(blank=True)
def __unicode__(self):
return self.name
views.py
def index(request, org_id=None):
help_def = HelpDefinition()
if org_id:
help_def = HelpDefinition.objects.get(org=org_id)
if request.method == 'POST':
form = FormHelp(request.POST)
if form.is_valid():
help_def.save()
messages.success(request, 'Saved!')
else:
messages.error(request, 'Ugh')
else:
form = FormHelp(request=request, initial=initial_data)
return {
'form': form,
}
forms.py
class FormHelp(forms.Form):
org = forms.CharField(widget=forms.HiddenInput, required=True)
help_type = forms.ChoiceField(abel='Text', required=True)
help_content = forms.CharField(label='Description', required=True, widget=forms.Textarea)
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(FormHelp, self).__init__(*args, **kwargs)
Due that you dont use ModelForm, you need to set your attributes one by one.
if request.method == 'POST':
form = FormHelp(request.POST)
if form.is_valid():
help_def.org = form.cleaned_data.get("org")
help_def.help_type = form.cleaned_data.get("help_type")
help_def.help_type = form.cleaned_data.get("help_content")
help_def.save()
I am using django-selectable and having trouble saving the "id" ('autocomplete_1') which represents the id for the category --- from the template.
models.py
class Category(models.Model):
cat_no = models.IntegerField(null=True, blank=True)
cat_txt = models.CharField(max_length=45)
def __unicode__(self):
return self.cat_txt
class Cattest(models.Model):
category = models.ForeignKey(Category)
info = models.CharField(max_length=35, blank=True)
lookups.py
class CategoryLookup(ModelLookup):
model = Category
search_fields = ('cat_txt__icontains', )
forms.py
class CategoryForm(forms.Form):
autocomplete = forms.CharField(
label='Type the name of a category (AutoCompleteWidget)',
widget=selectable.AutoCompleteWidget(CategoryLookup),
required=False,
)
autocompleteselect = selectable.AutoCompleteSelectField(
lookup_class=CategoryLookup,
label='Select a category (AutoCompleteField)',
required=False,
)
class CattestForm(forms.Form):
#model = cattest
#fields = ('category', 'info')
autocomplete = forms.CharField(
label='Type the name of a category (AutoCompleteSelectWidget)',
widget=selectable.AutoCompleteSelectWidget(CategoryLookup),
required=False,
)
info = forms.CharField(max_length=35, label="Information")
views.py
def cattest(request):
if request.method == 'POST':
form = CattestForm(request.POST)
if form.is_valid():
cattest = Cattest.objects.create(
category=form.cleaned_data['autocomplete_1'],
info=form.cleaned_data['info'],
)
# Always redirect after a POST
return http.HttpResponseRedirect('/bsmain/login_customer')
else:
if request.GET:
form = CattestForm(initial=request.GET)
else:
form = CattestForm()
return render_to_response('bsmain/form.html', {'form': form}, context_instance=RequestContext(request))
Traceback:
KeyError at /bsmain/cattest/
'autocomplete_1'
Request Method: POST
Request URL: http://127.0.0.1:8000/bsmain/cattest/
Django Version: 1.3.1
Exception Type: KeyError
Exception Value:
'autocomplete_1'
Exception Location: /home/bill/workspace/boatsite/../boatsite/bsmain/views.py in cattest, line 64
Python Executable: /usr/bin/python
Python Version: 2.6.5
Request information
GET No GET data
POST Variable Value
info u'44# Bruce'
csrfmiddlewaretoken u'9ffe49bd68be04087521e71e86a5bec0'
autocomplete_1 u'10'
autocomplete_0 u'Anchors'
The form cleaned_data dictionary is populated based on the field names. You should access the data from form.cleaned_data['autocomplete'].
Edit:
This would probably be easier by using a ModelForm:
class CattestForm(forms.ModelForm):
class Meta:
model = Cattest
fields = ('category', 'info', )
widgets = {
'category': selectable.AutoCompleteSelectWidget(CategoryLookup)
}
def cattest(request):
if request.method == 'POST':
form = CattestForm(request.POST)
if form.is_valid():
cattest = form.save()
# Always redirect after a POST
return http.HttpResponseRedirect('/bsmain/login_customer')
else:
initial = request.GET or None
form = CattestForm(initial=initial)
return render_to_response('bsmain/form.html', {'form': form}, context_instance=RequestContext(request))