views.py
report = Report.objects.get(user=user.id)
reportnotesform=ReportNotes(instance=report)
if request.method == 'POST':
locationnotesform=LocationNotes(request.POST,instance=report)
if locationnotesform.is_valid():
locationnotesform.save()
forms.py
class LocationNotes(forms.ModelForm):
other_location = forms.CharField(widget=forms.TextInput(attrs={'class':'ir-textbox'}))
location_description = forms.CharField(widget=forms.Textarea(attrs={'style':'width:20em'}))
models.py
class Report(models.Model):
user = models.ForeignKey(User, null=False)
location_description = models.TextField('Location description', null=True, blank=True)
other_location = models.CharField('Other', max_length=100, null=True, blank=True)
I am able to save the data,form is in update mode.
If i delete all data in field and click save,the field is not getting saved,means it is not taking null values.
Saving white space,but null is not saving.I want it to accept null values also.
Your model is fine but form would be giving you error.
Pass required=False to your field definitions in the form.
class LocationNotes(forms.ModelForm):
other_location = forms.CharField(required=False, widget=forms.TextInput(attrs={'class':'ir-textbox'}))
location_description = forms.CharField(required=False, widget=forms.Textarea(attrs={'style':'width:20em'}))
if i understand it correctly, In your LocationNotes form you need to make other_location and location_description optional also:
other_location = forms.CharField(
widget=forms.TextInput(attrs={'class':'ir-textbox'}),
required=False)
Related
I always use the following code to validate a form to prevent blank form submission. It always works in Django 1.8 but for some reason is not working in Django 2.2.
Here is the form
class CreateForm(forms.ModelForm):
class Meta:
model = Device
fields = ['category', 'item_name', 'quantity']
def clean_category(self):
category = self.cleaned_data.get('category')
if category == '':
raise forms.ValidationError('This field is required')
return category
def clean_item_name(self):
item_name = self.cleaned_data.get('item_name')
if item_name == '':
raise forms.ValidationError('This field is required')
return item_name
Here is the model
class Device(models.Model):
category = models.CharField(max_length=50, blank=True, null=True)
item_name = models.CharField(max_length=50, blank=True, null=True)
quantity = models.IntegerField(default='0', blank=False, null=True)
Thanks
I think the problem is that you did not check fro None, but nevertheless. I think you aim to do too much work yourself. You can just specify that the field is required=True [Django-doc], this will:
By default, each Field class assumes the value is required, so if you pass an empty value – either None or the empty string ("") – then clean() will raise a ValidationError exception.
So we can make the fields required with:
class CreateForm(forms.ModelForm):
category = forms.CharField(required=True, max_length=50)
item_name = forms.CharField(required=True, max_length=50)
class Meta:
model = Device
fields = ['category', 'item_name', 'quantity']
That being said, it is rather "odd" to specify blank=True [Django-doc] since this actually means that the field is not required in model forms. blank=True does not mean that the empty string is allowed, since even with blank=False, you can store empty strings in the field. A ModelForm will define (most of) its validation based on the model it "wraps", so that means that if you define the model better, you remove a lot of boilerplate code. Therefore I would advise eliminating blank=True.
Since you are specifying these fields as blank=True and null=True in your model so change those attributes
class Device(models.Model):
category = models.CharField(max_length=50, blank=False, null=False)
Or by default if you don't specify these blank and null attribute then it will be false by default so this should work also
class Device(models.Model):
category = models.CharField(max_length=50)
EDIT based on the comment:
Like the Willem said you need to check for None.You can do like this.
def clean_category(self):
category = self.cleaned_data.get('category')
if not category:
raise forms.ValidationError('This field is required')
return category
my form in forms.py is then passed to this method in my views.py, if I go into python shell and print objects from MyProfile, all of the fields show values except for nearbyzips, which shows None. As you can see below, I am trying to manually assign a value to nearbyzips when the form is saved.
inside views.py
#secure_required
#login_required
def profile_edit(request, username, edit_profile_form=EditProfileForm,
template_name='userena/profile_form.html', success_url=None,
extra_context=None, **kwargs):
profile = get_profile(user)
form = edit_profile_form(instance=profile, initial=user_initial)
if request.method == 'POST':
if form.is_valid()
cleanzipcode = form.cleaned_data['zipcode']
nearestzips = PostalCode.objects.distance(PostalCode.objects.get(code=cleanzipcode).location)
zip_codes = list(nearestzips.values_list('code', flat=True))
//print zip_codes
form.cleaned_data['nearbyzips'] = zip_codes
//print form.cleaned_data['nearbyzips']
profile=form.save()
return redirect(redirect_to)
models.py
class MyProfile(UserenaBaseProfile):
user = models.OneToOneField(User,
unique=True,
verbose_name=_('user'),
related_name='my_profile')
streetaddress=models.CharField(null=True, blank=True, max_length=30)
city = models.CharField(null=True, blank=True, max_length=20)
state = models.CharField(null=True, blank=True, max_length=20)
zipcode = models.IntegerField(_('zipcode'),
max_length=5, null=True, blank=True)
nearbyzips = models.IntegerField(null=True, blank=True, max_length=100)
phone=models.CharField(null=True, blank=True, max_length=16)
websiteurl=models.CharField(null=True, blank=True, max_length=38)
Something to keep in mind, if I go into python shell and run:
nearestzips = PostalCode.objects.distance(PostalCode.objects.get(code='97202').location
print nearestzips
It prints all the Postal Codes I would expect. So I'm not sure where exactly is broken. I don't see any errors in my logs.
UPDATE:
I have added print statements in my views. printing zip_codes and form.cleaned_data['nearbyzips'] both show:
[u'97202', u'97206', u'97214', u'97215', u'97239']
But it still does not appear to be saving to the form.
2 things stand out to me here.
Your form is created for some kind of profile model (get_profile_model()) -- does this profile model have a field called nearbyzips?
If your model does have a field called nearbyzips, explicitly include it (and all the fields you want to update) in a tuple/list of fields in your form class's inner Meta class.
Also, I don't see you calling the save method on your form class in your view function (i.e. form.save()).
Change this line:
tzips = PostalCode.objects.distance(PostalCode.objects.get(code='cleanzipcode').location)
to this:
tzips = PostalCode.objects.distance(PostalCode.objects.get(code=cleanzipcode).location)
I need to add a conditional piece of validation to my ModelForm.
Below is my Listing Model.
LISTING_TYPES = (
('event', 'event'),
('release', 'release')
)
class Listing(models.Model):
title = models.CharField(max_length=255, verbose_name='Listing Title')
type = models.CharField(max_length=255, choices=LISTING_TYPES, verbose_name='Listing Type')
slug = models.SlugField(max_length=100)
content = models.TextField(verbose_name='Listing Overview')
competition = models.TextField()
date_start = models.DateTimeField()
time_start = models.CharField(max_length=255)
date_end = models.DateTimeField()
time_end = models.CharField(max_length=255)
pub_date = models.DateTimeField('date published', auto_now_add=True)
venue = models.ForeignKey(Venue)
class ListingForm(ModelForm):
date_start = forms.DateField(input_formats=DATE_INPUT_FORMATS)
date_end = forms.DateField(input_formats=DATE_INPUT_FORMATS)
class Meta:
model = Listing
Venue should only be required if type == 'event'. If type == 'release', I want venue to be required=False
How can I go about this?
Thanks
First Listing.venue needs to allow null values
venue = models.ForeignKey(Venue, blank=True, null=True)
Your ModelForm then needs a clean method. Something like the following
def clean(self):
cleaned_data = super(ListingForm, self).clean()
venue = cleaned_data.get("venue")
type = cleaned_data.get("type")
if type == 'event' and not venue:
raise forms.ValidationError("A venue is required for events")
You mentioned doing ModelForm validation, but you should ask yourself if this rule is specific to creating objects with forms, or whether it is inherent in your data model itself. If it's the latter, then doing model validation makes more sense.
from django.core.exceptions import ValidationError
class Listing(models.Model):
...
def clean(self):
super(Listing, self).clean()
if self.type == 'event' and not self.venue:
raise ValidationError('A venue is required for events')
This will be called during ModelForm validation, so it will have the same effect there, but defining it on the model allows you to check the consistency of your data at any point with the Model.full_clean() method.
As Iain points out, you first need to allow null values for venue.
venue = models.ForeignKey(Venue, blank=True, null=True)
Given this model
class ScrapbookItem(models.Model):
scrapbook = models.ForeignKey(Scrapbook)
photo = models.ImageField(upload_to="uploads/scrapbook", blank=True, null=True, default=None)
comment = models.TextField(null=True, blank=True)
class ScrapbookItemDesignIdeaForm(forms.ModelForm):
class Meta:
model = ScrapbookItem
fields = ['scrapbook', 'comment']
When I submit the form, the photo field is not being set to None, why would that be?
I would guess that it's because you've got blank=True in your field definition. You probably don't need this, since you've got a default.
I've been trying to solve this problem for a couple of days now, getting quite desperate. See the commented out code snippets for some of the things I've tried but didn't work.
Problem: How can I limit the values in the category field of the IngredientForm to only those belonging to the currently logged in user?
views.py
#login_required
def apphome(request):
IngrFormSet = modelformset_factory(Ingredient, extra=1, fields=('name', 'category'))
# Attempt #1 (not working; error: 'IngredientFormFormSet' object has no attribute 'fields')
# ingrformset = IngrFormSet(prefix='ingr', queryset=Ingredient.objects.none())
# ingrformset.fields['category'].queryset = Category.objects.filter(user=request.user)
# Attempt #2 (doesn't work)
# ingrformset = IngrFormSet(prefix='ingr', queryset=Ingredient.objects.filter(category__user_id = request.user.id))
models.py:
class Category(models.Model):
name = models.CharField(max_length=30, unique=True)
user = models.ForeignKey(User, null=True, blank=True)
class Ingredient(models.Model):
name = models.CharField(max_length=30, unique=True)
user = models.ForeignKey(User, null=True, blank=True)
category = models.ForeignKey(Category, null=True, blank=True)
counter = models.IntegerField(default=0)
forms.py:
class IngredientForm(ModelForm):
class Meta:
model = Ingredient
fields = ('name', 'category')
UPDATE: I've made some progress but the solution is currently hard-coded and not really usable:
I found out I can control the categoryform field via form class and then pass the form in the view like this:
#forms.py
class IngredientForm(ModelForm):
category = forms.ModelChoiceField(queryset = Category.objects.filter(user_id = 1))
class Meta:
model = Ingredient
fields = ('name', 'category')
#views.py
IngrFormSet = modelformset_factory(Ingredient, form = IngredientForm, extra=1, fields=('name', 'category'))
The above produces the result I need but obviously the user is hardcoded. I need it to be dynamic (i.e. current user). I tried some solutions for accessing the request.user in forms.py but those didn't work.
Any ideas how to move forward?
You don't need any kind of custom forms. You can change the queryset of category field as:
IngrFormSet = modelformset_factory(Ingredient, extra=1, fields=('name', 'category'))
IngrFormSet.form.base_fields['category'].queryset = Category.objects.filter(user__id=request.user.id)
Category.objects.filter(user=request.user)
returns a list object for the initial value in your form which makes little sense.
Try instead
Category.objects.get(user=request.user)
or
Category.objects.filter(user=request.user)[0]