I am trying to validate a form using django forms. I have the following model:
class Session(models.Model):
# id = AutoField(primary_key=True) added automatically.
sport = models.ForeignKey('Sport', unique=False, blank=False, null=False, to_field='sport', on_delete=models.CASCADE, )
hostplayer = models.ForeignKey(User, unique=False, blank=False, null=False, on_delete=models.CASCADE, related_name='member_host', )
guestplayer = models.ForeignKey(User, unique=False, blank=True, null=True, on_delete=models.CASCADE, related_name='member_guest', )
date = models.DateField(blank=False, null=False, )
time = models.TimeField(blank=False, null=False, )
city = models.ForeignKey('City', unique=False, blank=False, null=False, to_field='city', on_delete=models.CASCADE, )
location = models.CharField(max_length=64, unique=False, blank=False, null=False, )
price = models.FloatField(unique=False, blank=False, null=False, default=0, )
details = models.TextField(unique=False, blank=True, null=True, )
def __unicode__(self):
return unicode(self.id)
and the following form:
class CreateSessionForm(forms.Form):
sport = forms.CharField()
date = forms.DateTimeField()
time = forms.TimeField()
city = forms.CharField()
location = forms.CharField()
price = forms.FloatField(required=False, initial=0, )
details = forms.CharField(required=False, )
def clean_price(self):
prc = self.cleaned_data['price']
if prc is None:
return 0
return prc
There is some frontend validation but I want to use the is_valid() functionality as well. I have the following piece of code in views.py:
if request.method == "POST":
form = CreateSessionForm(data = request.POST)
if form.is_valid():
# Create session object.
session = Session.objects.create(sport=Sport.objects.get(sport = form['sport'].data), hostplayer = request.user, guestplayer = None,
date = form['date'].data, time = form['time'].data, city = City.objects.get(city=form['city'].data),
>>> location = form['location'].data, price = form['price'].data, details = form['details'].data)
session.save()
# Return to the session page if successful.
return HttpResponseRedirect('/session/' + str(session.id) + '/')
Everything is working fine, except when the price I receive is ''. I want to allow this and default to 0. However, I receive the following error on the line marked with >>>:
could not convert string to float
When debugging that line, it appears that the value of price in form does not get updated (it appears to be '').
How could I change the value of price in the form to 0 when '' is passed? What would be the best way to go about doing this?
I have been searching for a way to fix this for 3 hours now without success. This is the first time I am using forms in django so I may very well be missing something completely obvious.
Any help will be greatly appreciated.
Fetch the values from form.cleaned_data, instead of using form['fieldname'].data
For example:
date = form.cleaned_data['date']
See the docs on processing the data from a form for further details.
There might be more than one problem, but the most obvious one that stands out is this:
price = modes.FloatField(..., blank=False, ...)
in your Session model.
Set blank=True to allow the form field to be blank. The ORM will then use your default=0 when saving if the form field was blank.
Related
This the views.py file.
How can i display the appointments made by the current logged in user?
def user(request):
client = Client.objects.all()
appointments = Appointment.objects.all()
context = {'appointments': appointments, 'client': client,
}
return render(request, 'users/user.html', context)
Here is my Models.py. I need to display the appointments by a user when they are logged in to their profile.
class Appointment(models.Model):
CATEGORY = (
('Plumbing', 'Plumbing'),
('Electrical', 'Electrical'),
('Cleaning', 'Cleaning'),
)
STATUS = (
('Pending', 'Pending'),
('Delivered', 'Delivered'),
)
user = models.ForeignKey(Client, null=True, on_delete=models.SET_NULL)
name = models.CharField(max_length=200, null=True)
worker = models.ForeignKey(Worker, null=True, on_delete=models.SET_NULL)
category = models.CharField(max_length=200, null=True, choices=CATEGORY)
task_date = models.DateField(_("Task Date"), blank=True, null=True)
task_location = models.CharField(max_length=200, null=True)
date_created = models.DateTimeField(auto_now_add=True, null=True)
status = models.CharField(max_length=200, null=True, choices=STATUS)
budget = models.FloatField(null=True)
task_description = models.CharField(max_length=1000, null=True)
task_image = models.ImageField(
null=True, blank=True, help_text='Optional.')
def __str__(self):
return str(self.user)
instead of using all() in your query use filter()
all() gives you all the entries in the table.
do something like this:
appointments = Appointment.objects.filter(user = request.user)
the left side "user" inside the filter must be a column in the Appointment model/table. you can pass multiple parameters inside the filter.
Yea it worked. but i had to create a one to one relatioship between appointment and User
I'm calling an API to update the my liked_products many to many model in Django but, when calling the prod ID to add the item to the list, I get the error:
AttributeError at /api/customer/like_product/
'ReturnDict' object has no attribute 'liked_products'
Here is my API:
#csrf_exempt
def updated_liked_products(request):
customer = get_user(request)
if not customer:
return JsonResponse({'invalid token'})
customer_details = CustomerDetailSerializer(CustomerDetails.objects.get(
customer=customer)).data
customer_details.liked_products.add(request.data['prodId'])
customer_details.save()
return JsonResponse({"success": 'updated'})
Customer Details Model:
age = models.IntegerField(default="21", blank=True)
address = models.CharField(
default='', max_length=254, null=True, blank=True)
nick_name = models.CharField(
default='', max_length=254, blank=True)
average_order = models.FloatField(default="0.0", blank=True)
completed_orders = models.IntegerField(default="0", blank=True)
customer = models.ForeignKey(
Customer, on_delete=models.CASCADE)
customer_type = MultiSelectField(
choices=CUSTYPE, default=CUSTYPE, max_length=100)
current_selfie = models.ImageField(
upload_to='sefies/', blank=True, default='')
email_confirmed = models.BooleanField(default=False)
last_signin = models.DateTimeField(default=timezone.now)
liked_products = models.ManyToManyField('Product')
needs_help_with = MultiSelectField(
choices=CATEGORIES, max_length=1000, default='')
phone = models.CharField(
I am using Postman to update the data like this so I can see the liked product field but, cannot access it.:
You're having this error because you're trying to access liked_products attribute on a serialized data that is an instance of ReturnDict and not CustomerDetails.
It seems like there is not much point in the serializer usage in this API so you should be able to achieve what you want with just this:
#csrf_exempt
def updated_liked_products(request):
customer = get_user(request)
if not customer:
return JsonResponse({'invalid token'})
customer_details = CustomerDetails.objects.get(customer=customer)
customer_details.liked_products.add(request.data['prodId'])
return JsonResponse({"success": 'updated'})
I have created a CustomerRegistration model and I want that if the phone no exists in the database, then all the details of the customer will display automatically in form.
here is my models.py
class CustomerRegistration(models.Model):
name = models.CharField(max_length=254, null=False)
email = models.EmailField(max_length=254, null=False)
date_of_birth = models.DateTimeField(null=False)
country_id = models.ForeignKey('accounts.Country', null=False, on_delete=models.CASCADE, related_name='Country')
state_id = models.ForeignKey('accounts.State', null=False, on_delete=models.CASCADE, related_name='State')
cities_id = models.ForeignKey('accounts.City', null=False, on_delete=models.CASCADE, related_name='city')
address = models.CharField(max_length=254, null=False)
refernce_by_person_name = models.CharField(max_length=254, null=False)
refernce_by_person_contact_no = models.IntegerField(null=True)
phone_no = models.IntegerField(null=False, primary_key=True)
alternate_no = models.IntegerField(null=False)
hobbies = models.CharField(max_length=254)
def __str__(self):
return self.name
Have a look at making queries in the django documentation. You will want to make a query to your databse, and if you get any results, populate your form with the correct info.
This would look something like:
from .models import CustomerRegistration
results = CustomerRegistration.objects.all().filter(phone=given_number)
then, if there are any results, you can use it to populate your form!
You can query like this to understand that user has phone number or not or something like that:
CustomerRegistration.objects.filter(phone_no__isnull=False)
isnull specifies that a field is none or not
i want to allow the user to change a value in his order from the data base
The idea is when the user press the delete button the value of visible changes from yes to no and he won't be able to see it on the profile
i managed to pull out all the user's orders
but i couldn't find a way to make the button change the value for the order of that current user only
is there any way to do such thing??
models.py
class Order(models.Model):
status_ch = [('in process', 'in process'), ('complete', 'complete')]
visible_ch = [('yes', 'yes'), ('no', 'no')]
status = models.CharField(
choices=status_ch, max_length=20, null=True, blank=False, default='in process')
user = models.ForeignKey(
User, on_delete=models.CASCADE, null=True, blank=True)
saller = models.CharField(blank=True, max_length=200)
product = models.CharField(blank=True, max_length=200)
currency = models.CharField(blank=True, max_length=200)
name = models.CharField(max_length=200, null=True, blank=False)
phone = models.FloatField(null=True, blank=False)
amount = models.FloatField(null=True, blank=False)
email = models.EmailField(null=True, blank=True)
accountId = models.TextField(default='', blank=False)
date = models.DateField(default=datetime.date.today)
image = models.ImageField('Label')
visible_for_saller = models.CharField(
choices=visible_ch, max_length=20, null=True, blank=False, default='yes')
visible_for_buyer = models.CharField(
choices=visible_ch, max_length=20, null=True, blank=False, default='yes')
def __str__(self):
return self.saller
views.py
#login_required
def profile(request):
orders = Order.objects.filter(user=request.user)
return render(request, 'app/profile.html', {'orders': orders})
First of all, you are using the visible attributes as booleans, so I recommend doing:
visible_for_saller = models.BooleanField(default=True)
visible_for_buyer = models.BooleanField(default=True)
Then, if I understood it well, you don't want to delete the order, just make it invisible for the user right?
If that's the case, the button you want to make have to call a view in which you just change the visible_for_buyer attribute, right? this could be the view:
def delete_order_for_buyer(request, pk):
user = request.user # you get the loged user
order = Order.objects.get(pk=pk) # you get the order through the pk
if order.user == user: # you check if the user is the owner of the order
order.visible_for_buyer = False # set the attr to false
order.save() # save that specific object
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) # you redirect to the page you came (you can change this for whatever you want)
else:
raise PermissionDenied() # in case someone that is not the user tries to execute that view through the url you make, it will raise an error.
Then you just need to add the url you want for it like:
path('order/<pk>/delete/', views.delete_order_for_buyer, name='delete-order'),
And finally on the view where you list all the orders (in case you have many, you can make an if statement in which you check if the visible_for_buyer is true or false:
{% if order.visible_for_buyer %}
show content here
{% endif %}
With all that little information you gave I had to asume lots of things but I suppose this will help you
In my django project I have 3 models, simplified for this example: Contact, WorkRelation and Group objects.
Contact
class Contact(BaseModel):
title = models.CharField(max_length=30, blank=True)
initials = models.CharField(max_length=10, blank=True)
first_name = models.CharField(max_length=30, blank=True)
prefix = models.CharField(max_length=20, blank=True)
surname = models.CharField(max_length=30)
def get_workrelations(self):
workrelations = apps.get_model('groups', 'WorkRelation')
return workrelations.objects.filter(contact=self)
def get_organisations(self):
output = ""
strings = []
wr = self.get_workrelations()
for relation in wr:
group = relation.group
name = group.name
strings.append(s)
if len(strings) > 0:
output = ", ".join(strings)
return output
WorkRelation
class WorkRelation(BaseModel):
contact = models.ForeignKey(Contact, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
function = models.CharField(max_length=40, blank=True)
email_address = models.EmailField()
phone_number = models.CharField(max_length=13, blank=True)
description = models.TextField(max_length=400, blank=True)
Group
class Group(BaseModel):
group_type = models.ForeignKey(GroupType, on_delete=models.CASCADE)
name = models.CharField(max_length=60, unique=True)
street_name = models.CharField(max_length=40, blank=True)
house_number = models.CharField(max_length=10, blank=True)
The problem with this setup is that it becomes extremely slow when I want to call get_organisations() on a large contact set. For example: when trying to list all my contacts (600 for my demo set), and call get_organisations(), about 1250 queries are needed.
I found that you can prevent this by using prefetch_data(), but somehow I can't get this working in my setup. I tried to replace my query for
queryset = Contact.objects.prefetch_related('workrelation_set')
But this didn't speed it up (against my presumption). Do you guys know if it is even possible to speed this up?
Change your get_organisations code to this:
def get_organisations(self):
return ', '.join(
workrelation.group.name for workrelation
in self.workrelation_set.all()
)
And use this query for fetching Contact objects:
Contact.objects.prefetch_related('workrelation_set__group')
This will return the result with a single query.