Issue rendering django for on template with bootstrap - django

I am trying to render my django forms in the template using bootstrap and I keep getting an error:
BoundField' object has no attribute 'fields'
This is what I try:
{% for field in layer_form %}
{{ field | as_bootstrap }}
{% endfor %}
If I try this:
{{ layer_form|as_bootstrap }}
then it works. But I need to loop through the form fields and append some if statements in between.
Any idea what's going on here?
The above works with another form but not with this one:
lass ResourceBaseForm(TranslationModelForm):
"""Base form for metadata, should be inherited by childres classes of ResourceBase"""
owner = forms.ModelChoiceField(
empty_label="Owner",
label="Owner",
required=False,
queryset=Profile.objects.exclude(
username='AnonymousUser'),
widget=autocomplete_light.ChoiceWidget('ProfileAutocomplete'))
_date_widget_options = {
"icon_attrs": {"class": "fa fa-calendar"},
"attrs": {"class": "form-control input-sm"},
"format": "%Y-%m-%d %H:%M",
# Options for the datetimepickers are not set here on purpose.
# They are set in the metadata_form_js.html template because
# bootstrap-datetimepicker uses jquery for its initialization
# and we need to ensure it is available before trying to
# instantiate a new datetimepicker. This could probably be improved.
"options": False,
}
date = forms.DateTimeField(
localize=True,
widget=DateTimePicker(**_date_widget_options)
)
temporal_extent_start = forms.DateTimeField(
required=False,
localize=True,
widget=DateTimePicker(**_date_widget_options)
)
temporal_extent_end = forms.DateTimeField(
required=False,
localize=True,
widget=DateTimePicker(**_date_widget_options)
)
poc = forms.ModelChoiceField(
empty_label="Person (fill form)",
label="Point Of Contact",
required=False,
queryset=Profile.objects.exclude(
username='AnonymousUser'),
widget=autocomplete_light.ChoiceWidget('ProfileAutocomplete'))
metadata_author = forms.ModelChoiceField(
empty_label="Person (fill form)",
label="Metadata Author",
required=False,
queryset=Profile.objects.exclude(
username='AnonymousUser'),
widget=autocomplete_light.ChoiceWidget('ProfileAutocomplete'))
keywords = TaggitField(
required=False,
help_text=_("A space or comma-separated list of keywords"),
widget=TaggitWidget('TagAutocomplete'))
regions = TreeNodeMultipleChoiceField(
required=False,
queryset=Region.objects.all(),
level_indicator=u'___')
regions.widget.attrs = {"size": 20}
With this simple form it works:
class UploadCSVForm(forms.Form):
def __init__(self, *args, **kwargs):
super(UploadCSVForm, self).__init__(*args, **kwargs)
self.fields['selected_country'] = forms.MultipleChoiceField(choices=get_country_names(), required=True)
title = forms.CharField(max_length=80, required=True)
LAYER_TYPE = (
('1', 'Global Layer'),
('2', 'Layer by Region'),
('3', 'Layer by Province'),
)
layer_type = forms.ChoiceField(choices=LAYER_TYPE, required=True)
csv = forms.FileField(required=True)
permissions_json = forms.CharField(max_length=500, widget=forms.HiddenInput())

Related

How do I get and pass context from one form to another based on primary/foreign key fields?

I am currently building a website that will allow the sale of mixing and mastering services. As it is a small set of services, I don't need a shopping cart or any elaborate form of ordering. Instead, I would like a customer details page (which informs my 'Customer' model), an order page where the customer selects what exactly they will be purchasing and uploads any relelvent files (which also informs my 'Order' model), and finally sends the customer to a stripe checkout page.
Currently, the Custome rdetails form is up and running and saving the data to the appropriate database model. Once they click continue, I am struggling to understand how to store the primary key of the Customer instance the user created upon filling out the form, and saving this data in the next form through the foreign key relationship.
Similarly, before being sent to Stripe checkout, I would like to create an 'Order Review' page, reviewing the details of their order. I'm not sure how to pull the primary key of the Order intance that was just created in order to for a Model view on the subsequent page. I believe what I;m missing in order to achieve either of these things is how to get the primary key of the database intsance created by the customer upon submitting the form.
Here is the code relevant to my question, incase I am going about this fundamentally wrong:
models.py
class Customer(models.Model):
first_name = models.CharField(max_length=200, null=False)
last_name = models.CharField(max_length=200, null=False)
phone = models.CharField(max_length=10)
email = models.EmailField(null=False)
date_created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.last_name
class Product(models.Model):
MIXMAS = 'Mixing and Mastering Package'
MASO = 'Mastering Only'
FEAT = 'Request a Feature'
TUT = 'Request a Tutor'
NONE = 'Select an option'
PRODUCT_NAME_CHOICES = [
(MIXMAS, 'Mixing and Mastering Package'),
(MASO, 'Mastering Only'),
(FEAT, 'Request a Feature'),
(TUT, 'Request a Tutor'),
(NONE, 'Select an option')
]
name = models.CharField(max_length=100, choices=PRODUCT_NAME_CHOICES, default=NONE)
stripe_product_id = models.CharField(max_length=100)
product_description = models.CharField(max_length=300, null=True)
def __str__(self):
return self.name
class Price(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name="prices")
stripe_price_id = models.CharField(max_length=100)
price = models.IntegerField(default=0) # cents
price_description = models.CharField(max_length=300, null=True)
class Meta:
ordering = ['price']
def get_display_price(self):
return "{0:.2f}".format(self.price / 100)
def __str__(self):
return '%s %s %s %s' % ("$", self.price, "-", self.price_description)
class Order(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE, verbose_name='Package Type: ')
price = models.ForeignKey(Price, on_delete=models.CASCADE, verbose_name="Number of stems: ")
cust_requests = models.TextField(max_length=500, null=True, verbose_name='Enter any specific requests here: (Leave blank if none): ')
reference_track = models.CharField(max_length=200, null=True, verbose_name='Reference Track (Leave blank if none): ')
music_file = models.FileField(upload_to='studio_orders/', verbose_name="Upload zipped music file: ")
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
order_date = models.DateTimeField(auto_now_add=True)
forms.py
from .models import Order, Customer, Product, Price
from django import forms
from django.urls import reverse_lazy
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit
from dynamic_forms import DynamicField, DynamicFormMixin
class OrderForm(DynamicFormMixin, forms.ModelForm):
def __init__(self, *args, **kwargs):
super(OrderForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
def price_choices(form):
product = form['product'].value()
return Price.objects.filter(product=product)
def initial_price(form):
product = form['product'].value()
return Price.objects.filter(product=product).first()
product = forms.ModelChoiceField(
queryset=Product.objects.all(),
initial=Product.objects.first(),
label= "Select a Product:",
widget= forms.RadioSelect(
attrs={
'hx-get' : 'prices',
'hx-target' : '#prices',
'hx-swap' : 'innerHTML'
}),
required=True,
)
prices = DynamicField(
forms.ModelChoiceField,
queryset=price_choices,
initial=initial_price,
label= "Select a price:"
)
cust_requests = forms.CharField(
label = 'Enter any specific requests here: (Leave blank if none): ',
required=False,
max_length=500
)
reference_track = forms.FileField(
label = 'Upload a reference track, if applicable.',
required=False,
)
music_file = forms.FileField(
label = 'Upload your project here. Please ensure project has been zipped prior to uploading.',
required=True
)
class Meta:
model= Order
fields = ['product', 'prices', 'cust_requests', 'reference_track', 'music_file']
class CustomerForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(CustomerForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
class Meta:
model = Customer
fields = ['first_name', 'last_name', 'phone', 'email']
urls.py
urlpatterns = [
path('', views.StudiosOverview.as_view(), name='musicstudios'),
path('order-details/', views.orderdetails, name='orderdetails'),
path('customer-details/', views.CustomerDetails.as_view(), name='custdetails'),
path('customer-details/upload', views.custupload, name='custupload'),
path('order-details/prices/', views.prices, name='prices'),
path('order-details/upload', views.orderupload, name='orderupload'),
path('cancel/', CancelView.as_view(), name='cancel'),
path('success/', SuccessView.as_view(), name='success'),
path('create-checkout-session/<int:pk>', CreateCheckoutSessionView.as_view(), name='create-checkout-session')
]
views.py
def orderdetails(request):
form = OrderForm()
context = {'form' : form}
template_name = 'musicstudios/order_details.html'
return render(request, template_name, context)
def prices(request):
form = OrderForm(request.GET)
return HttpResponse(form['prices'])
def custupload(request):
if request.POST:
form = forms.CustomerForm(request.POST, request.FILES)
success_url = reverse_lazy('orderdetails')
print(request.FILES)
if form.is_valid():
form.save()
else:
ctx = {'form' : form}
return HttpResponseRedirect(request, 'musicstudios/customer_details.html', ctx)
return HttpResponseRedirect(success_url)
def orderupload(request):
if request.POST:
form = OrderForm()
success_url = reverse_lazy('create-checkout-session')
if form.is_valid():
form.save()
else:
ctx = {'form' : form}
return render(request, 'musicstudios/order_details.html', ctx)
return reverse_lazy(success_url)
class StudiosOverview(View):
def get_context_data(self, **kwargs):
product = Product.objects.all()
prices = Price.objects.all()
context = super(StudiosOverview, self).get_context_data(**kwargs)
context.update({
"product": product,
"prices": prices
})
return context
def get(self, request):
context = {
'page_headline' : 'Studio Services'
}
context.update(sidebar_context)
return render(request, 'musicstudios/overview.html', context)
class CustomerDetails(CreateView):
form_class = forms.CustomerForm
template_name = 'musicstudios/customer_details.html'
stripe.api_key = settings.STRIPE_SECRET_KEY
class CreateCheckoutSessionView(View):
def post(self, request, *args, **kwargs):
product_id = self.kwargs["pk"]
product = Product.objects.get(id=product_id)
domain = "https://lewnytoonsstudios.com"
if settings.DEBUG:
domain = "http://127.0.0.1:8000"
checkout_session = stripe.checkout.Session.create(
line_items=[
{
# Provide the exact Price ID (for example, pr_1234) of the product you want to sell
'price': product.prices.stripe_price_id,
'quantity': 1,
},
],
mode='payment',
success_url=domain + '/success.html',
cancel_url=domain + '/cancel.html',
automatic_tax={'enabled': True},
)
return JsonResponse({
'id' : checkout_session.id
})
class SuccessView(TemplateView):
template_name = "success.html"
class CancelView(TemplateView):
template_name = "cancel.html"
Relevant HTML templates:
customer_details.html
<span class="flex-auto flex-col">
<form method="post" class="py-2" action="{% url 'custupload' %}" enctype="multipart/form-data"; return False;>
{% csrf_token %}
{{ form|crispy }}
<span class="flex justify-end">
<button class="lewny_button my-4" type="submit">Continue to Order</button>
</span>
</form>
</span>
</div>
order_details.html
<span class="flex-auto flex-col">
<form class="py-2" method="post" action="{% url 'orderupload' %}">
{% csrf_token %}
{{ form|crispy }}
<span class="flex justify-end">
<button class="lewny_button my-4" type="submit">Review Your Order</button>
</span>
</form>
</span>
</div>
I have tried several htmx methods of 'getting' the object but have been unable to achieve anything that works. I considered grabbing the most recent object from the database, but this seemed like a very insecure way to go about the solution.
This would seem a job for session variables. Once your customer is created by your save function, you can grab the id and place it in a session variable for later reference.
if form.is_valid():
customer = form.save()
request.session['customer_id'] = customer.id
You can access this wherever you need, either as request.session['customer_id'] (or request.sessions.get('customer_id') to return None if not set) in a functional view or self.request as above in a class based view.
More info in the docs

Django template tag show value not key

This is probably a simple answer, but I can't seem to find it in the docs.
How do I display the value of a choice field in template tags? Using .value did not work as I thought it may.
Right now it's just displaying the Key:
user_update
when I call this template tag on my html:
{{ ticket.current_status }}
from my forms.py:
current_status = ChoiceField(
label = "",
choices = STATUS_CHOICES,
widget = Select(attrs={
'class': 'h-10 flex flex-row justify-items-left',
})
)
and my views.py:
class StaffSupportTicketUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
...
def get_context_data(self, **kwargs):
context = super(StaffSupportTicketUpdateView, self).get_context_data(**kwargs)
context['search'] = SearchForm()
context['ticket'] = self.get_object()
return context
and my models.py:
class SupportTicketModel(Model):
...
current_status = CharField(default='new_ticket', choices=STATUS_CHOICES, max_length=35)
...
finally, my STATUS_CHOICES
STATUS_CHOICES = (
('new_ticket', 'New ticket submitted'),
('user_update', 'User updated ticket'),
('need_info', "Need more information"),
('completed', 'Completed'),
)
Use the get_FOO_display method that is dynamically created for your field because it has choices, it will return the human readable value of the field
{{ ticket.get_current_status_display }}

Django form validation not working for all the fields

new in the field and struggling with a form validation in practice. I have created a form which i use as data input for a search in the DB. Form validation is only being triggered for the first field while the others seems not to be taken in consideration, bellow the code:
Form description:
class SearchForm(forms.Form):
cnp_nbr = forms.IntegerField(label='CNP', widget=forms.TextInput(attrs={'class': 'form-control' }), required=False)
first_name = forms.CharField(label='First Name', widget=forms.TextInput(attrs={'class': 'form-control'}), required=False)
last_name = forms.CharField(label='Last Name', widget=forms.TextInput(attrs={'class': 'form-control'}), required=False)
class Meta():
model = Clients
fields = ('cnp_nbr','first_name','last_name')
def clean(self): # most used!!!
all_clean_data = super().clean()
cnp_nbr = all_clean_data['cnp_nbr']
first_name = all_clean_data['first_name']
last_name = all_clean_data['last_name']
if cnp_nbr is None or (first_name is None and last_name is None):
raise forms.ValidationError("Enter f1 or f2&f3")
super().clean()
Views:
class ClientsSearch(generic.FormView):
form_class = forms.SearchForm
template_name = "administration/clients_search.html"
success_url = reverse_lazy('administration:searchresults')
def form_valid(self, form):
self.request.session['cnp_nbr'] = form.cleaned_data['cnp_nbr']
self.request.session['first_name'] = form.cleaned_data['first_name']
self.request.session['last_name'] = form.cleaned_data['last_name']
return super().form_valid(form)
class SearchResults (generic.ListView):
model = models.Clients
template_name='administration/search_results.html'
context_object_name = 'all_search_results'
def get_queryset(self):
return self.model.objects.filter(
Q(cnp_nbr__exact=self.request.session['cnp_nbr']) | Q(first_name__exact=self.request.session['first_name']) & Q(last_name__exact=self.request.session['last_name'])
)
HTML for search form:
<form method="POST" >
{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-primary" id="search_submit" name = "search_submit" type="submit" > Search</button>
</form>
Validation is working only for cnp_nbr, i even tested them one by one.
This works :
if cnp_nbr is None:
raise forms.ValidationError("Enter field")
This doesnt
if first_name is None:
raise forms.ValidationError("Enter field")
Search is working just fine! Thanks in advance
That's because a not required IntegerField will be None if it's empty, whereas a not required CharField will be '' (the empty string) if it's empty. So you should not check last_name is None but just not last_name:
if cnp_nbr is None or not (first_name or last_name):
Note: Also I'd advise you to never directly assume the keys are present in the form's cleaned_data: Do first_name = all_clean_data.get('first_name') instead.
Note2: Why don't you just make cnp_nbr required since your ValidationError will trigger in any case if cnp_nbr isn't filled?

How to get option for select tag in forms.py from my model?

Please help me to solve this problem! I have form for job application and I have this in my
models.py:
class Vacancy(models.Model):
vacancy_title = models.CharField(max_length=100)
vacancy_description = models.TextField()
data = models.DateTimeField(default=timezone.now)
contact_person = models.CharField(max_length=50)
phone_number = models.CharField(max_length=30)
mail = models.EmailField();
def __str__(self):
return self.vacancy_title
A user must choose one of the vacancies
<select name="job_field" id="job_field">
{% for vacancy in vacancies %}
<option value="">{{ vacancy.vacancy_title }}</option>
{% endfor %}
</select>
Here is the forms.py:
from django import forms
from .models import Vacancy
CHOICES = (Vacancy.objects.all().values_list('vacancy_title', flat=True))
class ApplicantForm(forms.Form):
name = forms.CharField(max_length=50)
surname = forms.CharField(max_length=50)
email = forms.EmailField()
selected_position = forms.ChoiceField(choices=CHOICES)
And the views.py:
def send_resume(request):
vacancies = Vacancy.objects.all();
if request.method == 'POST':
form = ApplicantForm(request.POST)
if form.is_valid():
name = form.cleaned_data['applicant_name']
surname = form.cleaned_data['applicant_surname']
passport_number = form.cleaned_data['passport_number']
from_mail = form.cleaned_data['mail']
position = form.cleaned_data['position']
else:
form = ApplicantForm()
context = {'vacancies': vacancies}
return render(request, 'interactive/send_resume.html', context)
Now in the forms.py I cannot connect vacancy_title to the choice of the select group(Choice Field). How to do it?
You can just use ModelChoiceField.
selected_position = forms.ModelChoiceField(queryset=Vacancy.objects.all(), empty_label='(Nothing)')
It's more generic way
Use django-model-utils module. Your model code can look as below.
from model_utils import Choices
VACANCY_CHOICE = Choices(
('MANAGER', 'MANAGER', _('Development Manager')),
('SALES', 'SALES', _('Sales VP')),
)
class Vacancy(models.Model):
vacancy_title = models.CharField(choices=VACANCY_CHOICE, default=VACANCY_CHOICE.MANAGER,max_length=100)
Try to use {{form}} in your template.

check box always in unchecked mode after page reload

forms.py
Date_Format = (
('0', ' dd / mm / yyyy'),
('1', 'mm / dd / yyyy'),
)
Time_Format = (
('0', ' 12 hour AM / PM '),
('1', ' 24 hour '),
)
class SettingsForm(forms.ModelForm):
date_format = forms.ChoiceField(widget=forms.RadioSelect(), choices=Date_Format)
time_format = forms.ChoiceField(widget=forms.RadioSelect(), choices=Time_Format)
class Meta:
model = Settings
fields = ['date_format','time_format']
views.py
def date_format(request):
# settingsForm = SettingsForm({'user':request.user})
settings = Settings.objects.get(user=2)
settingsForm = SettingsForm(instance=settings)
# dateformatForm = DateFormatForm()
# timeformatForm = TimeFormatForm()
settingsForm = SettingsForm()
if request.method =='POST':
# dateformatForm = DateFormatForm(request.POST)
# timeformatForm = TimeFormatForm(request.POST)
settingsForm = SettingsForm(request.POST,instance=settings)
if (settingsForm.is_valid()):
settings=settingsForm.save()
# timeformatForm.save()
return redirect('/member/follow-up/')
return render_to_response( 'incident/date_format.html',
{
'about_menu': True,
'SettingsForm':settingsForm,
},
context_instance=RequestContext(request))
models.py
class Settings(models.Model):
user = models.ForeignKey(User, null=True)
date_format = models.CharField('Date format', max_length=100)
time_format = models.CharField('Time format', max_length=100)
template is
<form action="/member/date-format/" method="POST"> {% csrf_token %}
{{ SettingsForm.date_format }}
{{ SettingsForm.time_format }}
</form>
I am using models form here to store the form value in database.
If i select the radio button choice.the corresponding values are saving in database.But the checked radio button will uncheck if the page is reloaded.I don't know what logic to use to do this.
Moreover,is any way to save the values of radio button in template without using modelsForm.
Thanks
In your view:
def date_format(request):
# settingsForm = SettingsForm({'user':request.user})
settings = Settings.objects.get(user=2)
settingsForm = SettingsForm(instance=settings)
# dateformatForm = DateFormatForm()
# timeformatForm = TimeFormatForm()
settingsForm = SettingsForm()
....
You are resetting the settingsForm with empty form, which will show the form without any values from instance settings. You may want to remove that line.