Django, calendar - django

I need to use a calendar. I'm developing a website for house's rental, my first own web project, so, the idea is that the user selects an initial date and finish date, in the same month or any months (from January until April for example), and in the view (template) of the housing availability.
I want to show all months (12) and where is busy the house I'll show the days with some different color.
I'm searching and testing for Django calendar, but if somebody knows about it, please give me a hand :)
Thanks :)

Did you take a look at Django Schedule and Django SwingTime ?

Take a look at some of the calendar related exapmles here to see if they work for you:
http://www.djangosnippets.org/tags/calendar/
Also, you might consider using Python's HTMLCalendar as discussed here:
Creating a Flexible Monthly Calendar in Django

Here it is an example of overiding HTMLCalendar to display a queryset:
class QuerysetCalendar(HTMLCalendar):
def __init__(self, queryset, field):
self.field = field
super(QuerysetCalendar, self).__init__()
self.queryset_by_date = self.group_by_day(queryset)
def formatday(self, day, weekday):
if day != 0:
cssclass = self.cssclasses[weekday]
if date.today() == date(self.year, self.month, day):
cssclass += ' today'
if day in self.queryset_by_date:
cssclass += ' filled'
body = ['<ul>']
for item in self.queryset_by_date[day]:
body.append('<li>')
body.append('<a href="%s">' % item.get_absolute_url())
body.append(esc(item))
body.append('</a></li>')
body.append('</ul>')
return self.day_cell(cssclass, '%d %s' % (day, ''.join(body)))
return self.day_cell(cssclass, day)
return self.day_cell('noday', ' ')
def formatmonth(self, year, month):
self.year, self.month = year, month
return super(QuerysetCalendar, self).formatmonth(year, month)
def group_by_day(self, queryset):
field = lambda item: getattr(item, self.field).day
return dict(
[(day, list(items)) for day, items in groupby(queryset, field)]
)
def day_cell(self, cssclass, body):
return '<td class="%s">%s</td>' % (cssclass, body)

Related

Overriding Django's DurationField display

My model has a DurationField which is editable in Django Admin. I don't like how Django (inheriting its behavior from Python) displays negative durations, so I've tried to monkey patch it:
test = lambda: duration.duration_string(datetime.timedelta(seconds=-5)) == \
'-00:00:05'
if not test():
_duration_string = duration.duration_string
def duration_string(duration):
if duration.days < 0:
return '-' + _duration_string(-duration)
return _duration_string(duration)
duration.duration_string = duration_string
assert test()
This code gets run as part of my AppConfig.ready() method.
However, in Admin, the field still displays values formatted the default way. Is there some other way to customize how a DurationField's value is rendered in Admin?
At #Mehak's suggestion I tried the solution in this question. In fact, I tried just making a custom field that just bombs the program:
class CustomDurationField(models.DurationField):
def value_to_string(self, obj):
raise Exception()
def __str__(self):
raise Exception()
No exception is raised when viewing or editing the field, after making and applying the migration of course.
This answer led me on the right track. After performing the monkey patch, I had to define a custom model field that uses a custom form field...
import datetime
from django import forms
from django.db import models
from django.utils import duration
class CustomDurationFormField(forms.DurationField):
def prepare_value(self, value):
if isinstance(value, datetime.timedelta):
return duration.duration_string(value)
return value
class CustomDurationField(models.DurationField):
def formfield(self, **kwargs):
return super().formfield(**{
'form_class': CustomDurationFormField,
**kwargs,
})
If you don't want to monkey patch Django's django.utils.duration.duration_string, then you would just change CustomDurationFormField.prepare_value to call a separately defined version of it.
I'm not entirely sure why it requires so much effort to do this, but there it is.
Your answer also provides for customizing the input value (what's going in as the value). For example, if you wanted the input to be minutes instead of seconds, you could do:
def prepare_value(self, value):
if isinstance(value, datetime.timedelta):
val = value * 60
return val
In order to customize how the output is formatted for the post record in the admin, I did some interesting monkeypatching in admin.py - the reason being that duration_string had no formatting effect after deployment.
#admin.register(Post) # "Post" is the name of my database model
class PostAdmin(admin.ModelAdmin):
exclude = ('database_field') # hide this existing database field by excluding it, what you named the field replaces "database_field"
readonly_fields = ('database_field_readonly') # display new field as readonly
#admin.display(description="Estimated completion time")
def database_field_readonly(self, obj):
str_output = str(obj.database_field) # replace "database_field" with real existing database field name
str_output_list = str_output.split(':')
modify_hour_string = str_output_list[0] # this portion of text will include hours and any days
if(len(modify_hour_string) == 1): # if there were any days, the length of this portion will be greater than one
hour_num = modify_hour_string[0] # there were no days, we take the charAt 0 to get hours
else:
hour_num = modify_hour_string[len(modify_hour_string)-1] #capture the hour number (the number to the left of the colon which is len(string) - 1)
if hour_num == "1": #if hours is one, print "hour"
str_choice_hr = " hour "
else:
str_choice_hr = " hours "
if str_output_list[1] == "01": #if minutes is one, print "minute"
str_choice_min = " minute"
else:
str_choice_min = " minutes"
formatted_str = str_output_list[0] + str_choice_hr + str_output_list[1] + str_choice_min # any days will be automatically shown because of the ISO time format
return formatted_str
Any days, minutes, and hours will now be outputted like:
"5 days, 2 hours 10 minutes"

Manually dispatch a Django Class Based View

My application is very simple, it has a WeekArchiveView class based view:
class MenuWeekArchiveView(WeekArchiveView):
queryset = Menu.objects.all()
And its corresponding URL:
url(r'^(?P<year>[0-9]{4})/week/(?P<week>[0-9]+)/$', menu.views.MenuWeekArchiveView.as_view(), name="menu_week"),
I would like to have the home page of my application return the current week.
With old function based views, this was easy. I'd just have the home page return that function with the current week number as the arguments.
today = datetime.date.today()
current_week_number = today.isocalendar()[1]
current_year = today.year
return week_view(request, year=current_year, week=current_week_number)
A redirect wouldn't be acceptable because when someone bookmarks the page, they'll be bookmarking that week.
View.as_view() returns a proper view function you can use:
today = datetime.date.today()
current_week_number = today.isocalendar()[1]
current_year = today.year
return MenuWeekArchiveView.as_view()(request, year=current_year, week=current_week_number)

How to make previous day's date and today's date only accessible in date time picker in Odoo?

I am trying to check on a condition where the today's date is only accessible to get selected in the date time picker in Odoo and the code is as follows.
def onchange_date(self, cr, uid, ids, fdate, context=None):
if fdate:
if datetime.strptime(fdate, "%Y-%m-%d %H:%M:%S").date() <>
datetime.now().date():
return { 'value': { 'fdate': False } }
return fdate
I also wanted to make the previous day i.e yesterday's date to be available to the user to get selected along with today's date.
selected_date = datetime.strptime(fdate, "%Y-%m-%d %H:%M:%S").date()
yes_date = datetime.strptime(fdate, "%Y-%m-%d %H:%M:%S").relativedelta(days = -1).date()
today = datetime.now().date()
if selected_date <> today and selected_date <> yes_date
And add the import file for relative delte
If you only use Dates, you should use date instead of datetime, and if first if you only want a user use the date of today, get automatically the date of today and put it readonly, something like this:
...
import time
...
#here you got a field with the date of today.
date_today = fields.Date('Today is: ', default = lambda *a: time.strftime("%Y-%m-%d"), readonly = True)
And if you want what one user only be able to choose the days yesterday and today, it's a little bit more laborious, I know this is not the best way to do it but it work fine.
...
from openerp.exceptions import ValidationError
...
chosen_date = fields.Date('Chosen day: ', default = lambda *a: time.strftime("%Y-%m-%d"))
#api.onchange('chosen_date'):
def _onchange_chosen_date(self):
yesterday = str( int(time.strftime("%d")) - 1 )
if len(yesterday) == 1:
yesterday = '0' + yesterday
yesterday_date = time.strftime("%Y-%m-" + yesterday)
if self.chosen_date != time.strftime("%Y-%m-%d") or self.chosen_date != yesterday_date:
return { 'warning': {'title':"Warning", 'message':"You are only able to choose only yesterday and today...!"}}
EDIT
I only use V8, but I know something of V7 syntax!
1th.
...
import time
...
#here you got a field with the date of today.
date_today = fields.date('Today is: ', default = lambda *a: time.strftime("%Y-%m-%d"), readonly = True)
2th.
...
from openerp.osv import osv
...
chosen_date = fields.date('Chosen day: ', default = lambda *a: time.strftime("%Y-%m-%d"))
def _onchange_chosen_date(self, cr, uid, ids, chosen_date, context=None):
yesterday = str( int(time.strftime("%d")) - 1 )
if len(yesterday) == 1:
yesterday = '0' + yesterday
yesterday_date = time.strftime("%Y-%m-" + yesterday)
if self.chosen_date != time.strftime("%Y-%m-%d") or self.chosen_date != yesterday_date:
raise osv.except_osv(("Warning"),("You are only able to choose only yesterday and today...!"))
And in the XML:
<field name="chosen_date" on_change="_onchange_chosen_date(chosen_date)" />
I hope this can be helpful for you!!!

selectdatewidget set default month and day

How can I set selectDateWidget day and month options to default as 1st January but leave the year option intact.
Now I am doing:
day = datetime.date.today()
lessTime = forms.DateField(required=False, widget=SelectDateWidget(years=range(1980, 2013)), initial=day)
But this sets the default to the actual date. What can I change to give me the desired default options?
Thanks in advance
Make a custom widget e.g MySelectDateWidget
class MySelectDateWidget(SelectDateWidget):
def render(self, name, value, attrs=None):
from collections import namedtuple
date_tweak = namedtuple('Date', 'year month day')
date_value = date_tweak(None, 1, 1) #tweak to cheat SelectDateWidget's
#render method which expects a datetime object
return super(MySelectDateWidget, self).render(name, date_value, attrs)
and then replace:
lessTime = forms.DateField(required=False,
widget=SelectDateWidget(years=range(1980, 2013)), initial=day)
with:
lessTime = forms.DateField(required=False,
widget=MySelectDateWidget(years=range(1980, 2013)))

Django, actual month in queryset

how ill, get my register based in the current (actual) month in my queryset?, i have a ModelManager(), that just show the LIVE register status, but now i want to show the register with LIVE status and in the current (actual) month, i know that ill make something like .filter(...), but i dont know how get the current month..
model.py
#manager
class LiveNoticiaManager(models.Manager):
def get_query_set(self):
return super(LiveNoticiaManager,self).get_query_set().filter(status=self.model.LIVE_STATUS)
thanks guys.
http://docs.djangoproject.com/en/dev/ref/models/querysets/#month
You can
>>> import datetime
>>> today = datetime.date.today()
>>> MyModel.objects.filter(mydatefield__year=today.year,
mydatefield__month=today.month)
That's if you are only interested in gettting the month:
import datetime
today = datetime.date.today()
months = ['zero','January','February','March','April','May','June','July','August','September','October','November','December']
current_month = months[today.month]