I'm trying to build reservation app. I tried to find the solution but I have no idea.
I want to compare date of reservation from check_availibility with date from form. In form I've made:
check_in = forms.DateField(required=True, input_formats=["%Y-%m-%dT%H:%M", ])
check_out = forms.DateField(required=True, input_formats=["%Y-%m-%dT%H:%M", ])
import datetime
def check_availability(room, check_in, check_out):
avail_list = []
booking_list = Booking.objects.filter(room=room)
for booking in booking_list:
if booking.check_in > check_out or booking.check_out < check_in:
avail_list.append(True)
else:
avail_list.append(False)
return all(avail_list)
from hotelbooking.booking_funkctions.availibility import check_availability
class BookingView(FormView):
form_class = AvalilabilityForm
template_name = 'availability_form.html'
def form_valid(self, form):
data = form.cleaned_data
room_list = Room.objects.filter(category=data['room_category'])
available_rooms=[]
for room in room_list:
if check_availability(room, data['check_in'], data['check_out']):
available_rooms.append(room)
if len(available_rooms)>0:
room = available_rooms[0]
booking = Booking.objects.create(
user = self.request.user,
room = room,
check_in = data['check_in'],
check_out = data['check_out']
)
booking.save()
return HttpResponse(booking)
else:
return HttpResponse('this category of rooms are booked')
Since you're cleaning the date it should already convert the date strings to date objects, so you can do this:
def check_availability(room, check_in, check_out):
avail_list = []
booking_list = Booking.objects.filter(room=room)
for booking in booking_list:
if booking.check_in.date() > check_out.date() or booking.check_out.date() < check_in.date():
avail_list.append(True)
else:
avail_list.append(False)
return all(avail_list)
Just call the .date() method for the datetime one:
from datetime import datetime, date
is_today_today = datetime.now().date() == date.today() # valid
print(is_today_today) # True # (the only time that is real is the present)
Related
I seen many answer related this problem but I confused how to implement this.
My requirement is:
(Create)First create data with key and value:
{"pradip" : 80} and store in user_rate_details model field.
(Update)Second time append new data in this field :
{"pradip" : 80,"exz" : 70} and save it.
How to achieve this in my views..
models.py:
class UserPhoto(models.Model):
user = models.ForeignKey(to = User,on_delete = models.CASCADE,related_name='userPhoto')
......
rated_by = models.ManyToManyField(Profile,blank=True,related_name='rate_by')
user_rate_details = models.TextField() ⬅⬅⬅⬅⬅ Here store JSON data
created_date = models.DateTimeField(auto_now_add=True)
views.py:
class PhotoRate(APIView):
permission_classes = [IsAuthenticated]
def get_userPhoto(self,pk):
try:
return UserPhoto.objects.get(id = pk)
except UserPhoto.DoesNotExist:
raise Http404
def post(self,request,formate = None):
pk = request.data.get('photo_id')
rate = request.data.get('rate')
photo = self.get_userPhoto(pk)
???????? How to create or update Json data here???
return Response(??JSON DATA??)
Any other best way you know please tell me..
Thank you..
i really do not understand your question but if you intend to store json data in your model field, then you could try...
in your model:
import json
#property
def user_rate_details(self):
return json.loads(self.user_rate_details)
in your view:
pk = request.data.get('photo_id')
rate = request.data.get('rate')
photo = self.get_userPhoto(pk)
details = photo.user_rate_detail
details['rate'] = int(rate)
photo.user_rate_details = json.dumps(details)
photo.save(update_fields=['user_rate_details'])
return Response()
Create Text field in model and dump or load JSON data..
models.py:
import json
class UserPhoto(models.Model):
user = models.ForeignKey(to = User,on_delete = models.CASCADE,related_name='userPhoto')
......
rated_by = models.ManyToManyField(Profile,blank=True,related_name='rate_by')
user_rate_details = models.TextField(default="{}")
created_date = models.DateTimeField(auto_now_add=True)
#property
def rate_details(self):
return json.loads(self.user_rate_details)
views.py:
class PhotoRate(APIView):
permission_classes = [IsAuthenticated]
def get_userPhoto(self,pk):
try:
return UserPhoto.objects.get(id = pk)
except UserPhoto.DoesNotExist:
raise Http404
def post(self,request,formate = None):
pk = request.data.get('photo_id')
rate = request.data.get('rate')
photo = self.get_userPhoto(pk)
user_dict = photo.rate_details
user_dict[self.request.user.username] = int(rate)
photo.user_rate_details = json.dumps(user_dict)
photo.save(update_fields=['user_rate_details'])
return Response({"Success" : "Rate submited!!"},status=status.HTTP_200_OK)
def patch(self,request,formate=None):
pk = request.data.get('photo_id')
photo = self.get_userPhoto(pk)
rate_detail = photo.rate_details
return Response({"Rated Users" : rate_detail},status=status.HTTP_200_OK)
I am trying to adjust the cleaned_data that I get from the modelform to save certain values to the model based on the users input. These inputs can vary greatly, please see the model below along with the forms and views.
Should I call the model methods into the model form or should I do all the calculations in the modelForm itself. The figures can change depending on the contract selected and the start date selected as it will count the number of days and base it on this price for the contract, however if it is a half day then it will just divide the number by 2.
I am still new to Django but trying to figure out where all this information should be put, I am certainly clueless on this and trying to learn Django myself through real lifelike applications instead so appreciate your help.
Model
class AdminData(models.Model):
year1 = models.IntegerField()
year3 = models.IntegerField()
year1_fortnight = models.IntegerField()
year3_fortnight = models.IntegerField()
#property
def fortnight_dayrate_year1(self):
return self.year1_fortnight / weeksinyear / 5
#property
def fortnight_dayrate_year3(self):
return self.year3_fortnight / weeksinyear / 5
#property
def day_rate_year1(self):
return self.year1 / weeksinyear / 5
#property
def day_rate_year3(self):
return self.year3 / weeksinyear / 5
class Price(models.Model):
year_choice = Choices('1-Year Weekly', '3-Year Weekly','1-Year Fortnightly', '3-Year Fortnightly')
day_choice = Choices('Full Day', 'Half Day')
name = models.CharField(max_length=100)
contract = StatusField(choices_name='year_choice')
time_daily = StatusField(choices_name='day_choice')
start_date = models.DateField(default=datetime.now)
end_date = models.DateField(default=datetime(2021,3,31))
weeksinyear = 52
hours = 6.5
epoch_year = date.today().year
year_start = date(epoch_year, 1, 4)
year_end = date(epoch_year, 3, 31)
#property
def day_count(self):
return year_end - self.start_date
# #property
# def price_year1_weekly(self):
# if self.contract == self.year_choice[0]
# return AdminData.year1 * self.day_count
def __str__(self):
return self.name
Forms.py
class PriceForm(forms.ModelForm):
class Meta:
model = Price
fields = ['name', 'contract','time_daily','start_date']
Views.py
def price_detail(request):
if request.method == 'POST':
form = PriceForm(request.POST)
if form.is_valid():
price_instance = form.cleaned_data
form.save()
return render(request,'confirmation.html',{'form_data': price_instance})
else:
form = PriceForm()
return render(request, 'main.html', {'form': form})
For at the time of transaction calculations, the views.py is a good place for this, ie. a purchase, where the price is agreed upon at that moment and will never change.
If the business logic requires that the data updates the transaction, then the model is better.
views.py
def price_detail(request):
form = PriceForm(request.POST or None)
if form.is_valid():
price_instance = form.save() // this returns a saved instance
... do calculations here ...
price_instance.calculated_field = 1 + 1 // example calculations
price_instance.confirmed = False // consider adding a confirmed boolean, to not allow users to alter the data in the next step.
price_instance.save()
return render(request, 'confirmation.html', {'price_instance': price_instance})
else:
return render(request, 'main.html', {'form': form})
An example of doing the calculations every time the model is saved by overriding the model's save() method.
models.py
class Price(models.Model):
year_choice = Choices('1-Year Weekly', '3-Year Weekly','1-Year Fortnightly', '3-Year Fortnightly')
day_choice = Choices('Full Day', 'Half Day')
name = models.CharField(max_length=100)
contract = StatusField(choices_name='year_choice')
time_daily = StatusField(choices_name='day_choice')
start_date = models.DateField(default=datetime.now)
end_date = models.DateField(default=datetime(2021,3,31))
weeksinyear = 52
hours = 6.5
epoch_year = date.today().year
year_start = date(epoch_year, 1, 4)
year_end = date(epoch_year, 3, 31)
#property
def day_count(self):
return year_end - self.start_date
def save(self, *args, **kwargs):
... do calculations here ...
self.calculated_field = 1 + 1 // calculations
super().save(*args, **kwargs)
def __str__(self):
return self.name
I have one model Measurement, two forms MeassurementSystolicPressureForm and MeassurementDiastolicPressureForm. I want to make a view that allows user to add both of them to the database. Each has fields: username, measurement_date, value, measurement_type. When I fill forms on my webpage two records are added to the db, each has a good username and measurement_type, but measurement_date and value are the same for both records. Can you help me spotting what I'm doing wrong?
Here is my code:
models.py
class Measurement(models.Model):
value = models.IntegerField()
measurement_type = models.CharField(max_length=6, default='measurement', blank=True)
username = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
measurement_date = models.DateTimeField(default=datetime.now, editable=True)
forms.py
class MeassurementSystolicPressureForm(ModelForm):
class Meta:
model = Measurement
fields = ['value', 'measurement_date']
class MeassurementDiastolicPressureForm(ModelForm):
class Meta:
model = Measurement
fields = ['value', 'measurement_date']
views.py
def new_measurement(request):
if request.method == 'POST':
form_SP = MeassurementSystolicPressureForm(request.POST or None)
form_DP = MeassurementDiastolicPressureForm(request.POST or None)
if form_CS.is_valid() or form_CR.is_valid():
temp_S = form_SP.save(commit=False)
temp_S.username = request.user
temp_S.measurement_type = 'syspres'
temp_S.save()
temp_D = form_DP.save(commit=False)
temp_D.username = request.user
temp_D.measurement_type = 'diapres'
temp_D.save()
return redirect('/')
else:
form_SP = MeassurementSystolicPressureForm()
form_DP = MeassurementDiastolicPressureForm()
args = {'form_SP': form_SP, 'form_DP': form_DP}
return render(request, 'measurements.html', args)
If for example I submit data for:
Systolic Pressure:
value: 120
date: 2019-01-15 16:15:32
Diastolic Pressure:
value: 80
date: 2019-01-15 15:00:00`
In my database I have two records:
username: Julka, measurement_type:
syspres, value: 80, date: 2019-01-15 15:00:00
username: Julka, measurement_type: diapres, value: 80, date: 2019-01-15 15:00:00
I have no idea what to do.
In an HttpRequest object, the GET and POST attributes are instances of django.http.QueryDict. This type alone cannot determine which form was submitted. Your forms have the same fields, so then one form is valid, other form valid too. That's why you have measurement_date and value are the same for both records. To solve this problem, you can add additional hidden fields to your forms and look at them from which form was sent. Some like this:
class MeassurementSystolicPressureForm(ModelForm):
flag_Systolic = forms.IntegerField()
class Meta:
model = Measurement
fields = ['value', 'measurement_date']
def __init__(self, *args, **kwargs):
super(MeassurementSystolicPressureForm, self).__init__(*args, **kwargs)
self.fields['flag_Systolic'].widget = forms.HiddenInput()
class MeassurementDiastolicPressureForm(ModelForm):
flag_Diastolic = forms.IntegerField()
class Meta:
model = Measurement
fields = ['value', 'measurement_date']
def __init__(self, *args, **kwargs):
super(MeassurementDiastolicPressureForm, self).__init__(*args, **kwargs)
self.fields['flag_Diastolic'].widget = forms.HiddenInput()
and in your views:
def new_measurement(request):
if request.method == 'POST':
if 'flag_Systolic' in request.POST:
form_SP = MeassurementSystolicPressureForm(request.POST)
if form_SP.is_valid():
temp_S = form_SP.save(commit=False)
temp_S.username = request.user
temp_S.measurement_type = 'syspres'
temp_S.save()
return redirect('/')
elif 'flag_Diastolic' in request.POST:
form_DP = MeassurementDiastolicPressureForm(request.POST)
if form_DP.is_valid():
temp_D = form_DP.save(commit=False)
temp_D.username = request.user
temp_D.measurement_type = 'diapres'
temp_D.save()
return redirect('/')
else:
form_SP = MeassurementSystolicPressureForm()
form_DP = MeassurementDiastolicPressureForm()
args = {'form_SP': form_SP, 'form_DP': form_DP}
return render(request, 'measurements.html', args)
I know maybe it is too late but it might be helpful for other people facing the same problem.
One easier solution would be creating the object in the View and passing it to both forms:
from .models import Measurement
def new_measurement(request):
user=request.user #the authenticated user
if request.method == 'POST':
measurement=Measurement(username=user)
form_SP = MeassurementSystolicPressureForm(request.POST or None, instance=measurement)
form_DP = MeassurementDiastolicPressureForm(request.POST or None, instance=measurement)
if form_CS.is_valid() or form_CR.is_valid():
form_CS.save()
form_CR.save()
return redirect('/')
else:
form_SP = MeassurementSystolicPressureForm()
form_DP = MeassurementDiastolicPressureForm()
args = {'form_SP': form_SP, 'form_DP': form_DP}
return render(request, 'measurements.html', args)
I created a date range form to use in my Django views. In some of the views I use it in the date range is required, but not in others so I need the form to accept a required key word. I'm having trouble getting my form to recognize required=False.
The Django form:
class DateRangeForm(forms.Form):
def __init__(self, *args, **kwargs):
initial_start_date = kwargs.pop('initial_start_date')
initial_end_date = kwargs.pop('initial_end_date')
required_val = kwargs.pop('required')
input_formats = kwargs.pop('input_formats')
super(DateRangeForm,self).__init__(*args,**kwargs)
self.fields['start_date'].initial = initial_start_date
self.fields['start_date'].required = required_val
self.fields['start_date'].input_formats = input_formats
self.fields['end_date'].initial = initial_end_date
self.fields['end_date'].required = required_val
self.fields['end_date'].input_formats = input_formats
start_date = forms.DateTimeField(widget=forms.DateInput(attrs={'class':"form-control text-center"}))
end_date = forms.DateTimeField(widget=forms.DateInput(attrs={'class':"form-control text-center"}))
It's used in my Django view like this:
def Nominal_Request(request):
initial_end = Utils.addToDatetime(datetime.today().strftime("%Y/%m/%d"),weeks=6)
form_dict = {}
arg_dict = {}
message = message = {'last_url':'Nominal_Request'}
if request.method == 'POST':
daterange_form = DateRangeForm(request.POST,required=False,initial_start_date=None,initial_end_date=initial_end,input_formats=dateFormats)
if 'Range' in request.POST:
if daterange_form.is_valid():
#process the dates here....
WS = daterange_form.cleaned_data['start_date']
WE = daterange_form.cleaned_data['end_date']
#date processing continues....
args = {'Start':WS,'End':WE}
return Request_Results(request,args)
else:
daterange_form = DateRangeForm(required=False,initial_start_date=None,initial_end_date=initial_end,input_formats=dateFormats)
form_dict.update({'daterange_form':daterange_form})
return render(request,'InterfaceApp/Request_Nominal.html',form_dict)
It displays fine, but Django still thinks that both of the date range fields are required and won't let me submit the form with one or both of the fields empty.
Why is it not picking up on my required arg?
Is there a different widget or argument that will allow django to only show/take the year and month input instead of year, month and day?
Currently using SelectDateWidget.
There's a snippet here, which sets the day to 1 (presuming you've got a DateField that this value will end up in, you'll need to get some kind of day).
The code is like this (just in case Django snippets disappears):
import datetime
import re
from django.forms.widgets import Widget, Select
from django.utils.dates import MONTHS
from django.utils.safestring import mark_safe
__all__ = ('MonthYearWidget',)
RE_DATE = re.compile(r'(\d{4})-(\d\d?)-(\d\d?)$')
class MonthYearWidget(Widget):
"""
A Widget that splits date input into two <select> boxes for month and year,
with 'day' defaulting to the first of the month.
Based on SelectDateWidget, in
django/trunk/django/forms/extras/widgets.py
"""
none_value = (0, '---')
month_field = '%s_month'
year_field = '%s_year'
def __init__(self, attrs=None, years=None, required=True):
# years is an optional list/tuple of years to use in the "year" select box.
self.attrs = attrs or {}
self.required = required
if years:
self.years = years
else:
this_year = datetime.date.today().year
self.years = range(this_year, this_year+10)
def render(self, name, value, attrs=None):
try:
year_val, month_val = value.year, value.month
except AttributeError:
year_val = month_val = None
if isinstance(value, basestring):
match = RE_DATE.match(value)
if match:
year_val, month_val, day_val = [int(v) for v in match.groups()]
output = []
if 'id' in self.attrs:
id_ = self.attrs['id']
else:
id_ = 'id_%s' % name
month_choices = MONTHS.items()
if not (self.required and value):
month_choices.append(self.none_value)
month_choices.sort()
local_attrs = self.build_attrs(id=self.month_field % id_)
s = Select(choices=month_choices)
select_html = s.render(self.month_field % name, month_val, local_attrs)
output.append(select_html)
year_choices = [(i, i) for i in self.years]
if not (self.required and value):
year_choices.insert(0, self.none_value)
local_attrs['id'] = self.year_field % id_
s = Select(choices=year_choices)
select_html = s.render(self.year_field % name, year_val, local_attrs)
output.append(select_html)
return mark_safe(u'\n'.join(output))
def id_for_label(self, id_):
return '%s_month' % id_
id_for_label = classmethod(id_for_label)
def value_from_datadict(self, data, files, name):
y = data.get(self.year_field % name)
m = data.get(self.month_field % name)
if y == m == "0":
return None
if y and m:
return '%s-%s-%s' % (y, m, 1)
return data.get(name, None)
A Python 3 widget sample here https://djangosnippets.org/snippets/10522/.
Example usage :
class myForm(forms.Form):
# ...
date = forms.DateField(
required=False,
widget=MonthYearWidget(years=xrange(2004,2010))
)
I came across the same problem today and solved it by removing the day field via a css property and setting 1 as value for the day on clean up.
#id_my_date_field_day-button {
display: none;
}
I used a ModelForm with an UpdateView and therefore had initial data in my fields which made life a bit simpler because I always had a valid value for the day of my_date_field.
I've written a simpler version (https://djangosnippets.org/snippets/10943/) inheriting from django built-in SelectDateWidget.
In widgets.py:
import calendar
import datetime
from django.forms.widgets import HiddenInput, SelectDateWidget
from django.utils import datetime_safe
from django.utils.formats import get_format
class MonthYearWidget(SelectDateWidget):
def __init__(self, last_day=False, *args, **kwargs):
self.last_day = last_day
return super().__init__(*args, **kwargs)
def get_context(self, name, value, attrs):
context = super().get_context(name, value, attrs)
day_name = self.day_field % name
day_subwidget = HiddenInput().get_context(
name=day_name,
value=1,
attrs={**context["widget"]["attrs"], "id": "id_%s" % day_name},
)
context["widget"]["subwidgets"][0] = day_subwidget["widget"]
return context
def value_from_datadict(self, data, files, name):
value = super().value_from_datadict(data, files, name)
if self.last_day is True:
y = data.get(self.year_field % name)
m = data.get(self.month_field % name)
if y is not None and m is not None:
input_format = get_format("DATE_INPUT_FORMATS")[0]
monthrange = calendar.monthrange(int(y), int(m))
date_value = datetime.date(int(y), int(m), monthrange[1])
date_value = datetime_safe.new_date(date_value)
return date_value.strftime(input_format)
return value
kwargs:
last_day : if set to True, returns the last day of the month in the generated date, otherwise returns a date starting from the 1st day of the month
Usage example:
# models.py
from django.db import models
from django.utils.translation import gettext_lazy as _
class MyModel(models.Model):
start = models.DateField(
_("Start date"),
)
end = models.DateField(
_("End date"),
)
class Meta:
verbose_name = _("My model")
# forms.py
from django import forms
from .models import MyModel
from .widgets import MonthYearWidget
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
exclude = []
widgets = {
"start": MonthYearWidget(),
"end": MonthYearWidget(last_day=True),
}