I have a Django model with a FloatField, which I later base a form on. For some reason I get "'float' object has no attribute 'as_tuple'", and unfortunately I have no idea why do I get this error or how to fix it.
models.py:
class Course(models.Model):
title = models.CharField(max_length = 200)
author = models.ForeignKey(User,default=None, on_delete=models.SET_DEFAULT)
description = models.TextField(max_length=1000, blank=True)
tags = models.TextField(blank = True)
duration = models.FloatField(validators=(MinValueValidator(0.1),MaxValueValidator(12), DecimalValidator(max_digits=3,decimal_places=2)))
def __str__(self):
return self.title
forms.py:
class CourseForm(ModelForm):
class Meta:
model = Course
fields = ('title', 'description', 'price', 'duration', 'tags')
views.py:
#login_required
def create_course(request):
if request.method == "POST":
form = CourseForm(request.POST)
if form.is_valid():
form.save()
messages.info(request, f"Course created succesfully!")
else:
messages.error(request, "Something went wrong, please resubmit!")
form = CourseForm()
return render(request, "main/createcourse.html", {"form": form})
html:
{% extends 'main/header.html' %}
<body>
{% block content%}
<div class="container">
<form method="POST">
{% csrf_token %}
{{form.as_p}}
<br>
<button class="btn" type="submit">Create</button>
</form>
If you to modify an existing course, click <strong>here</strong> instead.
</div>
<br><br>
{% endblock %}
</body>
If you really need to use a FloatField, then you need to write your own validator:
def validate_decimals(value):
s = str(value)
d = decimal.Decimal(s)
if abs(d.as_tuple().exponent) > 2:
raise ValidationError(
_('%(value)s has more than 2 decimals. Please enter 2 decimals only.'),
params={'value': value},
)
Then, you add validators='validate_decimals' when you declare the FloatField.
Note that a float value cannot directly be converted to decimal. It should first be converted to string and then to decimal. See also:
Python float to Decimal conversion
There is a difference between a float and a Decimal. A Decimal encodes the data by storing the digits of a decimal number. You can however not perform DecimalValidation on a float, since due to rounding errors, it will add extra digits.
You thus can use a DecimalField [Django-doc] instead. Note that you thus need to pass Decimal objects in that case, not floats.
class Course(models.Model):
title = models.CharField(max_length = 200)
author = models.ForeignKey(User,default=None, on_delete=models.SET_DEFAULT)
description = models.TextField(max_length=1000, blank=True)
tags = models.TextField(blank = True)
duration = models.DecimalField(max_digits=3,decimal_places=2, validators=(MinValueValidator(0.1),MaxValueValidator(12), DecimalValidator(max_digits=3,decimal_places=2)))
def __str__(self):
return self.title
You might want to take a look at the DurationField [Django-doc] to store duration however, this will automatically use a timedelta, and store it as an integer for databases that do not support such types.
Related
I'm having some trouble displaying data from my database on the template in django
model:
class CityInfo (models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=200)
landmark_type = models.CharField(blank=True, max_length=30)
business = 'Business'
student = 'Student'
tourist = 'Tourist'
def __str__(self):
return self.name
relevant view:
def itemget(request):
data=CityInfo.objects.all()
return render(request,'CityApp/infopage.html', {'data': data})
relevant url:
url(r'itemget/$',views.itemget,{'template_name': 'CityApp/info_page.html'},name='itemget'),
infopage.html:
<ul>
{% for item in data %}
<li>
<h1>{{ item.name }}</h1>
</li>
{% endfor %}
<ul>
The above html results in a blank list and I have no idea why.
Try changing views.py to the following:
def itemget(request):
data = CityInfo.objects.all()
context={
'data': data
}
return render(request, "CityApp/infopage.html", context)
Try this :
def __str__(self):
return "%s" % self.name
I'm not sure because I'm on my old smartphone.
Otherwise, your def __str__ is well indented in your class ?
Are you using Python 2 or Python 3 ? str if for Python 3. Else you have to use __unicode__
EDIT :
From you urls.py file, you have :
url(r'itemget/$',views.itemget,{'template_name': 'CityApp/info_page.html'},name='itemget'),
Remove your template_name part which is already in your view and don't forget to add ^ before itemget
url(r'^itemget/$',views.itemget ,name='itemget'),
My goal
The following code is supposed to display a formset containing a certain number of TravellerForm then validate them and save the CompleteSubscription and his Traveller associated.
Only the main contact - first form - is supposed to have a mendatory phone number at the E.164 format validated by a regex.
Results of the following code
It correctly suppress the phone number field for other forms than the first and properly displays the fields I need.
Then, when I submit my form , the travellers are saved in my database, including the first although I put an invalid phone number in it. The subscription is correctly saved.
For fix this issue, I've overrided the clean_phone_number method, it seems working but it's giving me two errors and not only one as expected.
Phone number must be in E.164 format. Ex: +33123456789
Make sure that this value has a maximum of 16 characters (currently 143).
My problematic
Why does I need to override the clean_phone_number method to display the errors, aren't formsets supposed to call the clean method of theirs forms before saving ?
If it so, why is my clean_phone_number method called when I override it ?
I'm by the way interesting to know how could django count 143 character when I actually entered only 12 characters (I guess the deletion of a field could have destroyed a bit the count).
The code itself
There is the template,
<form method="post">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
{{ form.as_p }}
</br>
{% endfor %}
<input type="submit" value="Valider" />
</form>
The view,
def set_main_form(formset):
is_main = True
for form in formset:
if is_main:
is_main = False
else:
del form.fields['phone_number']
# Main contact is the first Travelller
def complete_subscription_create(request, base_pk):
base = BaseSubscription.objects.get(pk=base_pk)
number_forms = base.nb_adults + base.nb_children + base.nb_babies
TravellerFormSet = modelformset_factory(Traveller, form=TravellerForm,
extra=number_forms)
if request.method == 'POST':
formset = TravellerFormSet(request.POST, request.FILES)
set_main_form(formset)
if formset.is_valid():
base = BaseSubscription.objects.get(pk=base_pk)
subscription = CompleteSubscription(base_subscription=base)
subscription.save()
formset[0].instance.is_main_contact = True
for form in formset:
form.instance.subscription = subscription
formset.save()
return redirect('home')
else:
formset = TravellerFormSet()
set_main_form(formset)
return render(request, 'offerspace/completesubscription_form.html',
{'formset': formset})
The forms instanciated in the formset,
class TravellerForm(forms.ModelForm):
class Meta:
model = Traveller
fields = ('first_name', 'second_name', 'last_name',
'passport_country', 'phone_number')
# For some reasons, the regex validator works when I uncomment this
#def clean_phone_number(self):
#cleaned_data = super(TravellerForm, self).clean()
#return cleaned_data
The model of the TravellerForm
class Traveller(models.Model):
first_name = models.CharField(max_length=128)
second_name = models.CharField(max_length=128, blank=True)
last_name = models.CharField(max_length=128)
# This field is in E.164 Format, see https://en.wikipedia.org/wiki/E.164
# for more informations about this format
phone_error_message = """
Phone number must be in E.164 format.
Ex: +33123456789
"""
phone_regex = RegexValidator(regex=r'^\+?1?\d{8,15}$',
message=phone_error_message,
code='invalid_phone_number')
phone_number = models.CharField(validators=[phone_regex], blank=True,
max_length=16)
passport_country = models.ForeignKey(Country)
is_main_contact = models.BooleanField(default=False)
subscription = models.ForeignKey(CompleteSubscription)
And the CompleteSubscription model instanciated in the view,
class CompleteSubscription(models.Model):
base_subscription = models.OneToOneField(BaseSubscription)
final_price = models.PositiveIntegerField(default=0)
I am working on a product app on Python 2.7 / Django 1.7.
I have a model for product namely 'product_profile' and I want to allow my customer (end user) to ask any thing regarding specific products using a form.
However I am unable to allow user to automatically select the product (foreign key) and the customer has to select from a drop-down which quite irrational. I have also assigned the foreign key in url-variable.
here is my code:
MODEL.PY
class ProductProfile(models.Model):
category = models.ForeignKey(Category)
brand = models.ForeignKey(Brand)
product_name = models.CharField(max_length=128)
model_name = models.CharField(max_length=128)
generation = models.CharField(max_length=128)
processor = models.CharField(max_length=128)
ram = models.DecimalField(max_digits=2, decimal_places=0)
hdd = models.DecimalField(max_digits=6, decimal_places=2)
optical_drive = models.CharField(max_length=128)
display = models.CharField(max_length=128)
card_reader = models.CharField(max_length=128)
blue_tooth = models.CharField(max_length=128)
web_cam = models.CharField(max_length=128)
warranty = models.CharField(max_length=128)
price = models.DecimalField(max_digits=9, decimal_places=2)
condition = models.TextField()
product_image = models.ImageField(upload_to=update_Product_image_filename)
post_date = models.DateTimeField(db_index=True, auto_now_add=True)
# Override th __unicode__() method to return out something meaningful!
def __unicode__(self):
return self.product_name
class Customer_ps_contact(models.Model):
name = models.CharField(max_length=128)
email = models.EmailField(max_length=75)
subject = models.CharField(max_length=128 )
product = models.ForeignKey(ProductProfile)
message = models.TextField()
phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$', message="Phone number must be entered in the format:
'+999999999'. Up to 15 digits allowed.")
phone_number = models.CharField(validators=[phone_regex], blank=True, max_length=15) # validators should be a
list
def __unicode__(self):
return self.name
FORM.PY
class Customer_ps_contactForm(forms.ModelForm):
class Meta:
model = Customer_ps_contact
product = forms.ModelChoiceField(queryset=ProductProfile.objects.all(),
widget=forms.HiddenInput())
fields = ('name','email', 'product','subject','message', 'phone_number')
VIEWS.PY
def product_inquiry(request, product_id):
product = ProductProfile.objects.get(pk=product_id)
if request.method == 'POST':
#form = Customer_ps_contactForm(request.POST, initial = {'product': product})
#form = Customer_ps_contactForm(initial = {'product': product.id})
form = Customer_ps_contactForm(request.POST)
if form.is_valid():
form_data_dict = form.cleaned_data
print form_data_dict['product']
mail_customer_enquriy(form_data_dict) # Function to send email to admin
thank_u_customer(form_data_dict) # Function to send email to customers
form = form.save(commit=False)
form.product = product
form.save()
return home(request)
else:
print ("form is not valid")
print (form.errors)
else:
form = Customer_ps_contactForm()
context_dict = {'form':form, 'product': product}
return render(request, 'product/product_inquiry2.html',context_dict)
URL Patterns
urlpatterns = patterns('',
url(r'^inquiry/(?P<product_id>\d+)/$', views.product_inquiry, name='price'), # Only relevent url given
)
Template : product_inquiry2.html
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block body_block %}
{% block title %}Product Inquiry{% endblock %}
<div class="row">
<div class="col-md-10 col-md-offset-1">
<h2 style="font-weight:bold">Enquiry regarding '{{product.product_name}}'</h2>
<hr>
<form id="contact_form" method="post" action=""/>
{% csrf_token %}
{{ form | crispy }}
<input class="btn btn-primary pull-right " type="submit" name="submit" value="Submit the Message" />
</form>
</div>
</div>
{% endblock %}
What should I do?
You know what the product is from the id in the url, so there's no need to include it in your form.
To check that the product exists in the database, you can use the get_object_or_404 shortcut.
def product_inquiry(request, product_id):
product = get_object_or_404(ProductProfile, pk=product_id)
Then leave out 'product' from your list of fields, and remove the ModelChoiceField with hidden input widget.
class Customer_ps_contactForm(forms.ModelForm):
class Meta:
model = Customer_ps_contact
fields = ('name','email','subject','message','phone_number')
You are already setting the product when you save it, but it would be clearer to use the variable name instance to make it clearer what's going on. If you change your mail_customer_enquriy and thank_u_customer methods to use the instance instead of cleaned_data, then you won't have to do anything with form.cleaned_data.
if form.is_valid():
instance = form.save(commit=False)
instance.product = product
instance.save()
mail_customer_enquriy(instance) # Function to send email to admin
thank_u_customer(instance) # Function to send email to customers
return home(request)
Hi I have to following Models.py
class Question(models.Model):
user = models.ForeignKey(User)
article = models.ForeignKey(Article)
number = models.CharField("문제번호", max_length=10, null=True, blank=True)
q_type = models.CharField("문제유형", max_length=15)
question = models.TextField("문제내용")
answer = models.TextField("답안", null=True, blank=True)
reference = models.TextField("참고사항", null=True, blank=True)
def __str__(self):
return "%s번: %s" % (self.number, self.question)
class Professor(models.Model):
question = models.OneToOneField(Question, null=True, blank=True, related_name="related_professor")
articles = models.ManyToManyField(Article, null=True, blank=True)
name = models.CharField("교수이름", max_length=20)
def __str__(self):
return "%s" % (self.name,)
Views.py:
def read_q_table(request, board_id, article_id):
article = get_object_or_404(Article, id=article_id)
context = {
"boards" : Board.objects.all(),
"board_id" : board_id,
"questions" : Question.objects.all().order_by("number"),
"article" : article,
"professor" : Professor.objects.all()
}
return render(request, "q_table.html", context)
Template:
{% if questions %}
{% for question in questions %}
<div class="list-group-item">
<div class="row text-center">
<div class="col-xs-2 col-md-2">{{ question.related_professor.name }}</div>
</div>
</div>
{% endfor %}
{% else %}
What I want is to access professor name field in template. I have passed in context the list of "question" class objects to template, and I would like to use OneToOneField attribute somehow to access related professor name in template.
According to Accessing Django OneToOneField in templates?, {{ question. related_professor.name }} should work, but it doesn't. Can anyone help?
Thanks.
Or, it could be a problem with saving the professor data in the first place. The following code takes form input and submit them to save them.
Professor.objects.get(name=professor).question = question_instance
Professor.objects.get(name=professor).save()
These two lines in def submit_question may raise an eyebrow but I am not sure. Here I am trying to get the related professor instance and update its question field(a OneToOneField that relates to Question class).
def submit_question(request, board_id, article_id):
article = get_object_or_404(Article, id= article_id)
try:
professor = request.POST["professor"].strip()
q_type = request.POST["q_type"].strip()
question = request.POST["question"].strip()
number = request.POST["number"].strip()
reference = request.POST["reference"].strip()
if request.POST['q_type']== "주관식":
answer = request.POST['d_answer'].strip()
else:
answer = request.POST['m_answer'].strip()
except KeyError:
request.session["error"] = "올바른 요청이 아닙니다."
return redirect("read_article", board_id, article_id)
if professor and q_type and question:
question_instance = article.question_set.create(q_type = q_type, question = question, user_id = request.user.id)
Professor.objects.get(name=professor).question = question_instance
Professor.objects.get(name=professor).save()
if number:
question_instance.number = number
if answer:
question_instance.answer = answer
if reference:
question_instance.reference = reference
question_instance.save()
else:
request.session["error"] = "출제교수, 문제유형 및 문제는 필수 입력 항목입니다."
return redirect("read_article", board_id, article_id)
return redirect("read_q_table", board_id, article_id)
These two lines are suspect:
Professor.objects.get(name=professor).question = question_instance
Professor.objects.get(name=professor).save()
The second line will get the Professor from the database again, and it won't have your question instance attached anymore when you save it. Try this instead:
prof = Professor.objects.get(name=professor)
prof.question = question_instance
prof.save()
python=2.7, django=1.11.13
In my html I am not able to display my condition choices from my models.py
When filling the form, the user is not able to choose a condition because they are not displayed.
models.py
class Books(models.Model):
book_name = models.CharField(max_length=100)
book_condition = models.ForeignKey('Condition')
def __unicode__(self):
return self.book_name
class Condition(models.Model):
NEW = 'new'
USED = 'used'
COLLECTIBLE = 'collectible'
CONDITION_CHOICES = (
(NEW, 'New'),
(USED, 'Used'),
(COLLECTIBLE, 'collectible'),
)
book = models.ForeignKey(Books)
condition = models.CharField(max_length=10, choices=CONDITION_CHOICES)
def __unicode__(self):
return self.condition
views.py
def add_book(request):
if request.method == 'GET':
context = {
'form': BookForm()
}
if request.method == 'POST':
form = BookForm(request.POST)
if form.is_valid():
form.save()
context = {
'form': form,
}
return render(request, 'add_book_form.html', context=context)
add_book_form.html
{% extends 'base.html' %}
{% block body %}
<h3>Add Book </h3>
<form action="" method="post">
{% csrf_token %}
{{ form}}
<br/>
<input class="button" type="submit" value="Submit"/>
</form>
{% endblock %}
And this is my form, I'm not sure what I am missing.
form
from django.forms import ModelForm
from .models import Books, Condition
class BookForm(ModelForm):
class Meta:
model = Books
fields = '__all__'
class ConditionForm(ModelForm):
class Meta:
model = Condition
fields = '__all__'
The form you're passing to the view is a BookForm, the BookForm contains a ForeignKey field to the Condition model, so the options in the select will be instances of the Condition model.
You would need to preemptively create the Condition model instances, via the admin interface or the shell, and then you could see the conditions on the select, but that won't help, because your Condition instance needs to be associated to a Book, and that makes me think your software is badly designed.
Let me propose a solution:
class Book(models.Model):
"""
This model stores the book name and the condition in the same
table, no need to create a new table for this data.
"""
NEW = 0
USED = 1
COLLECTIBLE = 2
CONDITION_CHOICES = (
(NEW, 'New'),
(USED, 'Used'),
(COLLECTIBLE, 'Collectible'),
)
name = models.CharField(max_length=100)
condition = models.SmallIntegerField(choices=CONDITION_CHOICES)
def __unicode__(self):
return "{0} ({1})".format(self.book_name, self.condition)
class BookForm(ModelForm):
class Meta:
model = Book
fields = '__all__'
Now the conditions are saved as an integer (like it would be if you used foreign keys) and your software is easier to understand and develop.
Try to use Django widgets. For example:
class BookForm(forms.Form):
categories = (('Adventure', 'Action'),
('Terror', 'Thriller'),
('Business', 'War'),)
description = forms.CharField(max_length=9)
category = forms.ChoiceField(required=False,
widget=forms.Select,
choices=categories)