Creating different completion paths using form wizard - Django - django

I was following the tutorial online, but I am stuck when trying to conditionally show steps in my form wizard.
views.py
def silver_ad_selected(wizard):
cleaned_data = wizard.get_cleaned_data_for_step('0') or {}
return cleaned_data.get('ad_type') == '2'
def platinum_ad_selected(wizard):
cleaned_data = wizard.get_cleaned_data_for_step('0') or {}
return cleaned_data.get('ad_type') == '3'
class AddWizard(SessionWizardView):
def done(self, form_list, **kwargs):
return render_to_response('business/done.html', {
'form_data': [form.cleaned_data for form in form_list],
})
urls.py:
add_forms = [AddForm1, AddForm2, AddForm3]
urlpatterns = patterns('listings.views',
url(r'^addWizard/$', AddWizard.as_view(add_forms,
condition_dict = {
'2': silver_ad_selected or premium_ad_selected
})),
.......
forms.py
class AddForm1(forms.Form):
TYPE_CHOICES = (
('1','Basic'),
('2','Silver'),
('3','Platinum')
)
ad_type = forms.ChoiceField(choices=TYPE_CHOICES, widget=forms.RadioSelect)
class AddForm2(forms.Form):
category = forms.ModelChoiceField(queryset = Category.objects.all())
city = forms.ModelChoiceField(queryset = City.objects.all())
name = forms.CharField(max_length = 200)
address = forms.CharField(max_length = 200)
slogan = forms.CharField(max_length=140)
phone = forms.CharField(max_length=10)
website = forms.URLField()
email = forms.EmailField()
class AddForm3(AddForm2):
twitter = forms.CharField(max_length=100)
facebook = forms.URLField()
description = forms.CharField(widget=forms.Textarea)
Basically, I only want to show the last step if the user chooses either the "Silver" option or the "Platinum" option, which is selected in step 1. Right now, no matter what I choose, only the first two steps/forms are shown.
I think that my silver_ad_selected and platinum_ad_selected methods might be the problem, but I am not sure.
Thanks

Try changing your urls.py:
add_forms = [AddForm1, AddForm2, AddForm3]
urlpatterns = patterns('listings.views',
url(r'^addWizard/$', AddWizard.as_view(add_forms,
condition_dict = {
'2': lambda wizard: wizard.silver_ad_selected() or wizard.premium_ad_selected()
})),

Related

Django Form and two forms with foreign key

I have these models:
class Customers(models.Model):
ID = models.AutoField(primary_key=True)
...
def __str__(self):
return str(self.ID)
class CustomerAddresses(models.Model):
ID = models.AutoField(primary_key=True)
...
CustomerNoID = models.ForeignKey('Customers', on_delete=models.CASCADE)
def __str__(self):
return str(self.ID)
and my view:
def add_customer_view(request):
user_id = request.user.id
last_customerno = Customers.objects.filter(UserID=user_id).order_by('CustomerNo').last()
if not last_customerno:
# return '0001'
last_customerno = 1000
if last_customerno == 1000:
customerno_int = 1000
else:
customerno_int = last_customerno.CustomerNo + 1
# if this is a POST request we need to process the form data
if request.method == 'POST':
customer_form = CustomerForm(request.user.id, request.POST)
customer_address_form = CustomerAddressesForm(request.user.id, request.POST)
if customer_form.is_valid():
new_customer = customer_form.save(commit=False)
new_customer.save()
if customer_address_form.is_valid():
new_address = customer_address_form.save(commit=False)
new_address.CustomerNoID = new_customer
new_address.save()
return HttpResponseRedirect('/backend/kunder/')
else:
customer_form = CustomerForm(request.user.id, initial={'CustomerNo': customerno_int})
customer_address_form = CustomerAddressesForm(request.user.id)
return render(
request,
'backend/add_customer.html',
{
'title': 'WestcoastShop - Backend',
'customer_form': customer_form,
'customer_address_form': customer_address_form
}
)
But just the Customer is creating not the address I think the form is missing the CustomerNoID and I think I got the right way but after 6 hrs I give up maybe here is a smart guy how finds the error.
regards.
I changed the form and added the second one in a modal so I can save the two models nondependent.

How can i create custom validation in django model forms

I want to create a custom form validation in Django forms. I am able to do it normal Django forms but unable to do it in model forms.
my Django form code is
class Post_Article(forms.Form):
title = forms.CharField(label = 'Title',max_length = 100)
abstract = forms.CharField(widget = forms.Textarea, max_length = 300)
body = forms.CharField(widget = forms.Textarea)
image = forms.ImageField(required = False)
hash_tags = forms.CharField(max_length = 50,required = False)
def no_of_hash_tags(self):
cleaned_data = super().no_of_hash_tags()
tags = cleaned_data.get('hash_tags')
if tags:
tags = split(str(tags))
if len(tags) > 5:
raise forms.ValiadationError('Maximum 5 tags are allowed')
the Django model is
class PostsArticle(models.Model):
title = models.CharField(max_length=255)
pub_date = models.DateTimeField(default= timezone.now)
abstract = models.TextField()
body = models.TextField()
image = models.ImageField(upload_to=('images/'),blank=True)
user = models.ForeignKey(User , on_delete = models.CASCADE)
hash_tags = models.CharField(max_length = 50,blank= True)
def _str_(self):
return self.title
def get_absolute_url(self):
return reverse('home')
def summary(self):
return self.absract[:200]
def pub_date_pretty(self):
return self.pub_date.strftime('%b %e %Y')
def link_tags(self):
cleaned_data = super().link_tags
tags = cleaned_data.get['hash_tags']
for tag in tags:
hashing(tag,"PostsArticle")
After some discussion on stack overflow I updates my Django forms to
class Post_Article(forms.ModelForm):
title = forms.CharField(label = 'Title',max_length = 100)
abstract = forms.CharField(widget = forms.Textarea, max_length = 300)
body = forms.CharField(widget = forms.Textarea)
image = forms.ImageField(required = False)
hash_tags = forms.CharField(max_length = 50,required = False)
class Meta:
model = PostsArticle
fields=("title", "abstract", "body", "image", "hash_tags")
def clean(self)
:
cleaned_data=super(Post_Article, self).clean()
tags = cleaned_data.get("hash_tags")
if tags:
tags = split(str(tags))
if len(tags) > 5:
raise forms.ValidationError('Maximum 5 tags are allowed')
return cleaned_data
Now I am unable to get how can I use it with my current class used in views.py
class FeedUpdateView(LoginRequiredMixin, UserPassesTestMixin , UpdateView):
model = FeedPosts
fields= ['body', 'image']
template_name= 'post/edit_Feed.html'
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
def test_func(self):
Posts = self.get_object()
if self.request.user == Posts.user:
return True
return False
I want to use my Django forms code instead of creating view from my model directly. I want to do it because I want to have some custom validation of a field as given in my forms code
kindly help how can I add form validation to my model
Cleaning a specific field attribute, you would have to call clean_<field_name>.
class Post_ArticleForm(ModelForm):
class Meta:
model = PostsArticle
fields = ['abstract', 'title', 'body', 'image', 'hash_tags']
def clean_hash_tags(self):
cleaned_data = super().clean_hash_tags()
tags = self.cleaned_data.get('hash_tags')
if tags:
tags = split(str(tags))
if len(tags) > 5:
raise forms.ValiadationError('Maximum 5 tags are allowed')
return cleaned_data
You need to override clean method for your ModelForm.
Example:
class Post_Article(forms.ModelForm):
...
hash_tags = forms.CharField(max_length = 50,required = False)
...
class Meta:
model = PostsArticle
fields=("title", "abstract", "body", "image", "hash_tags",)
def clean(self):
cleaned_data=super(Post_Article, self).clean()
tags = cleaned_data.get("hash_tags")
if tags:
tags = split(str(tags))
if len(tags) > 5:
raise forms.ValidationError('Maximum 5 tags are allowed')
return cleaned_data
the clean funtion is not getting invoked
Django forms is
class Post_Article(forms.ModelForm):
title = forms.CharField(label = 'Title',max_length = 100)
abstract = forms.CharField(widget = forms.Textarea, max_length = 300)
body = forms.CharField(widget = forms.Textarea)
image = forms.ImageField(required = False)
hash_tags = forms.CharField(max_length = 50,required = False)
class Meta:
model = PostsArticle
fields=("title", "abstract", "body", "image", "hash_tags")
def clean(self):
print(hello)
cleaned_data=super(Post_Article, self).clean()
tags = cleaned_data.get("hash_tags")
if tags:
tags = split(str(tags))
if len(tags) > 5:
raise forms.ValidationError('Maximum 5 tags are allowed')
return cleaned_data
the clean funtion is not getting invoked
the formview for the same is
class PostCreateView(LoginRequiredMixin,FormView):
form_class = Post_Article
template_name= 'post/post.html'
success_url = '/'
def form_valid(self, form):
form.instance.user = self.request.user
print(form.instance.user)
return super().form_valid(form)
the formview is in the views.py

How to set initial value in the form

Hey guys how can i set initial value in my form field, let say the user click "BidForm" in the search form, i want the BidForm value will be the value of ProjectName in the other form...
here's my code in my search views
def search_views(request):
project_list = ProjectNameInviToBid.objects.all()
query = request.GET.get('query')
if query:
project_list = project_list.filter(ProjectName__icontains=query)
context = {
'project_list': project_list
}
return render(request, 'content/search_views.html', context)
and my other views
def project_name_details(request, sid):
majordetails = ProjectNameInviToBid.objects.get(id=sid)
if request.method == 'POST':
form = invitoBidForm(request.POST, request.FILES)
form.fields['ProjectName'].initial = majordetails
if form.is_valid():
form.save()
messages.success(request, 'File has been Uploaded')
else:
form = invitoBidForm()
args = {
'majordetails': majordetails,
'form': form
}
return render(request,'content/invitoBid/bacadmininvitoBid.html', args)
my form.py
class invitoBidForm(ModelForm):
class Meta:
model = InviToBid
fields = ('ProjectName','NameOfFile', 'Contract_No', 'Bid_Opening',
'Pre_Bid_Conference', 'Non_Refundable_Bidder_Fee',
'Delivery_Period',
'Pdf_fileinvi',)
and my models.py
class ProjectNameInviToBid(models.Model):
ProjectName = models.CharField(max_length=255, verbose_name='Project Name', null=True)
DateCreated = models.DateField(auto_now=True)
def __str__(self):
return self.ProjectName
class InviToBid(models.Model):
today = date.today()
ProjectName = models.ForeignKey('ProjectNameInviToBid', on_delete=models.CASCADE)
NameOfFile = models.CharField(max_length=255, verbose_name='Name of File')
Contract_No = models.IntegerField(verbose_name='Contract No')
def __str__(self):
return self.NameOfFile
First, I shall praise your documentation. Most people fail to provide the important code.
You can add something like this to your code here that will do what you require.
An example from my own code
if request.method == 'GET' and request.user.is_authenticated:
study = Study.objects.get(pk=studyID)
form = ContactForm(initial={'from_email': request.user.email, 'subject': "Study: " + study.name ,'message': study_message.format(request.user.get_short_name(), request.user.get_full_name())})
How you should change your code
Change your code in your other views from this:
else:
form = invitoBidForm()
to
else:
form = invitoBidForm(initial={'ProjectName': <wherever your project name comes from>})

Set field form value from view

How to add field value manually from view?
model.py
class Connect(models.Model):
username = models.CharField(max_length=255)
password = models.CharField(max_length=255,null=True, blank=True)
conft = models.TextField(null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return unicode(self.username)
form.py
class NacmForm(ModelForm):
password = forms.CharField(widget=forms.PasswordInput,required = False)
conft = forms.Textarea()
class Meta:
model = Connect
fields = ['username', 'password','conft']
labels = {'conft':_('Config'),}
view.py
class config_static(View):
def post(self, request, *args, **kwargs):
formm = NacmForm(request.POST or None)
ipform = IpFormset(request.POST)
userValue = formm['username'].value()
passValue = formm['password'].value()
if ipform.is_valid() and formm.is_valid():
simpanForm = formm.save()
for form in ipform:
ipaddr = form.cleaned_data.get('ipaddr')
vendor = form.cleaned_data.get('vendor')
.......
//some code//
.......
simpanIp = form.save(commit=False)
simpanIp.connect_id = simpanForm
simpanIp.save()
simpanForm.save()
.........
//some code//
i want to set "conft" value manually, maybe like
configuration = "some config"
conft = configuration
i already tried
configuration = "some config"
NacmForm(initial={'conft': configuration })
or
formm.fields['conft'].initial = configuration
or
formm = NacmForm(request.POST, initial={"conft": configuration })
when i use that code above, the value isnt save to database, then i tried this
Connect.objects.create(conft=configuration)
its save to database but not in same row
formm.cleaned_data returns dictionary. So, you can add/update/remove keys manually. initial={} This is for rendering purposes (Which adds in html forms initial values value="something"). As far as i understand you want to modify incoming data when HTTP POST is made. Try like this.
class config_static(View):
def post(self, request, *args, **kwargs):
formm = NacmForm(request.POST or None)
ipform = IpFormset(request.POST)
userValue = formm['username'].value()
passValue = formm['password'].value()
if ipform.is_valid() and formm.is_valid():
# If both form is valid
formm.cleaned_data['conft'] = '<new_value>' # + this is added logic
simpanForm = formm.save()
for form in ipform:
ipaddr = form.cleaned_data.get('ipaddr')
vendor = form.cleaned_data.get('vendor')
.......
//some code//
.......
simpanIp = form.save(commit=False)
simpanIp.connect_id = simpanForm
simpanIp.save()
simpanForm.save()
.........
//some code//
forms.py
class NacmForm(ModelForm):
password = forms.CharField(widget=forms.PasswordInput,required = False)
# conft = forms.Textarea()
class Meta:
model = Connect
fields = ['username', 'password','conft']
labels = {'conft':_('Config'),}
Hope, it helps you.
so after googling, i just add this line
class config_static(View):
def post(self, request, *args, **kwargs):
formm = NacmForm(request.POST or None)
ipform = IpFormset(request.POST)
userValue = formm['username'].value()
passValue = formm['password'].value()
if ipform.is_valid() and formm.is_valid():
# If both form is valid
simpanForm = formm.save()
for form in ipform:
ipaddr = form.cleaned_data.get('ipaddr')
vendor = form.cleaned_data.get('vendor')
.......
//some code//
.......
simpanForm.conft = "ip route configuration" # i add this
simpanIp = form.save(commit=False)
simpanIp.connect_id = simpanForm
simpanIp.save()
simpanForm.save()
.........
//some code//

inlineformset_factory composed of ModelForm

Is it possible for an inlineformset_factory to take in a ModelForm as well as a model. When I try to run this I get an error message 'NoneType' object is not iterable.
Please help, I've spent an entire day trying to figure this out. Thanks.
Code:
Model.py
class FilterForm(ModelForm):
firstFilter = forms.BooleanField(label='First Filter', initial=False, required=False)
class Meta:
model = Filter
exclude = ('order')
class Controller(models.Model):
protocol = models.CharField('Protocol',max_length=64, choices=PROTOCOLS, default='http')
server = models.CharField('Server', max_length=64, choices=SERVERS, default='127.0.0.1')
name = models.CharField('Name', max_length=64)
def __unicode__(self):
return self.protocol + '://' + self.server + '/' + self.name
view.py
def controller_details(request, object_id):
controller = Controller.objects.get(pk=object_id)
controllerURI = controller.protocol + '://' + controller.server + '/' + controller.name
FilterFormSet = inlineformset_factory(Controller, FilterForm, extra=5)
if request.method == 'POST':
formset = FilterFormSet(request.POST, request.FILES, instance=controller)
if formset.is_valid():
filters = []
# Save all the filters into a list
forms = formset.cleaned_data
for form in forms:
if form:
protocol = form['protocol']
server = form['server']
name = form['name']
targetURI = form['targetURI']
filterType = form['filterType']
firstFilter = form['firstFilter']
if firstFilter == True:
aFilter = Filter(controller=controller, protocol=protocol, server=server, name=name, targetURI=targetURI, filterType=filterType, order=0)
else:
aFilter = Filter(controller=controller, protocol=protocol, server=server, name=name, targetURI=targetURI, filterType=filterType, order=-1)
filters.append(aFilter)
# Find the first filter in the list of filters
for index, aFilter in enumerate(filters):
if aFilter.order == 0:
break
if filters[index].targetURI:
test = "yes"
else:
for aFilter in filters:
aFilter.save()
else:
formset = FilterFormSet(instance=controller)
return render_to_response('controller_details.html', {'formset':formset, 'controllerURI':controllerURI}, context_instance=RequestContext(request))
UPDATE: If you intended to create a FormSet with Controller and Filter models where Filter holds a FK to the Controller, you need:
FilterFormSet = inlineformset_factory(Controller, Filter, form=FilterForm)
Note that in your code above, you're only passing the the Controller model class, which caused some confusion.