Manually dispatch a Django Class Based View - django

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)

Related

Dynamic search using date

Can any one please help me i want to search my expenses income which is in my models.py using date wise dynamic search where user will input date and he will see the result in template i dont know how to code that template ..I tried form but not working.. :(
my views.py
def date_page(request):
f_date = '2018-12-05'
t_date = '2019-09-12'
from_date = datetime.datetime.strptime(f_date, "%Y-%m-%d").date()
to_date = datetime.datetime.strptime(t_date, "%Y-%m-%d").date()
date_queryset = Add.objects.filter(date__range=(from_date, to_date))
print (date_queryset)
return render (request , 'date_page.html',)
Pass the date value as URL parameter and fetch it using request.GET as,
def date_page(request):
f_date = request.GET.get("f_date")
t_date = request.GET.get("t_date")
date_queryset = Add.objects.filter(date__range=(f_date, t_date))
print(date_queryset)
return render(request, 'date_page.html', )
Example URL : /api/end-point/expenses/?f_date=2018-12-05&t_date=2019-09-12

Django objects.filter(date...) - template implementation

I've got a function which sends an email with expenses. Everything works fine, but I have no idea how to implement a small part of the code into a template and give for the user an option to choose a period of time.
For example: user should choose a year and month from the template.
def mail_from_web(request):
email = EmailMessage('Your expenses', 'Hello there. Some text', 'email#from',
['email#to'])
attachment_csv_file = StringIO()
writer = csv.writer(attachment_csv_file, delimiter=',')
writer.writerow(['Date', 'Customer', 'Car park'])
for call in Call.objects.filter(date__year='2019', date__month='04').order_by('date'):
writer.writerow([call.date_start.strftime("%Y-%m-%d"), call.customer, call.expenses])
email.attach('expenses.csv', attachment_csv_file.getvalue(), 'text/csv')
email.send(fail_silently=False)
return render(request, 'calls/mail_sent.html')
Instead of this:
objects.filter(date__year='2019', date__month='04')
create a form
class MyForm(forms.Form)
year = forms.IntegerField(
widget = forms.NumberInput(min=2019)
)
month = forms.IntegerField(
widget = forms.NumberInput(min=1, max=12))
Add it to your context to pass to the template.
Show in the template
...
{{form}}
...
In the view
year = int(request.POST['year'])
month = int(request.POST['month'])
Change Call.objects.filter(date__year='2019', date__month='04') to Call.objects.filter(date__year=year, date__month=month)
I've just realised you're not using int for the year and month so you'll need to modify accordingly.

Calcul Time on django

I have the following code:
def index(request):
events_list = Timesheet.objects.filter(owner = request.user.pk, week = datetime.datetime.now().isocalendar()[1]).order_by('-working_hour')
total_hours_week = Timesheet.objects.annotate(total_hours_per_week=Sum('working_hour')).filter(owner = request.user.pk, week = datetime.datetime.now().isocalendar()[1])
return render(request, "timesheet/index.html", {'events_list': events_list, 'total_hours_week': total_hours_week})
the total_hours_week retun the current error:
You cannot use Sum, Avg, StdDev, and Variance aggregations on date/time fields in sqlite3 since date/time is saved as text.
Do you know how to fix ?
thanks per advance
You can check if the current DB engine is sqlite3 or not, and calculate annotations programmatically in case that is needed:
from django.conf import settings
def index(request):
db_engine = settings.DATABASES['default']['ENGINE']
if db_engine = 'django.db.backends.sqlite3':
total_hours_week = [] # Calculate annotation programmatically
else:
total_hours_week = Timesheet.objects.annotate(total_hours_per_week=Sum('working_hour')).filter(owner = request.user.pk, week = datetime.datetime.now().isocalendar()[1])
events_list = Timesheet.objects.filter(owner = request.user.pk, week = datetime.datetime.now().isocalendar()[1]).order_by('-working_hour')
return render(request, "timesheet/index.html", {'events_list': events_list, 'total_hours_week': total_hours_week})
However, if you are using sqlite3 only for development, and you need to work with time aggregations a lot, I strongly recommend you to setup a PostgreSQL/MySql server for your development environment, as it saves you a lot of time and headache in long run.

How can I show elapsed time in Django

So, I'm trying to show elapsed time on a page for recent-visited history. On my model, I have the following attribute.
models.py
class History(models.Model):
...
created_on = models.DateTimeField(auto_now_add=True)
...
I already checked the date documentation, but it doesn't have a way to represent elapsed time from creating time to now. Doesn't Django support the feature? then should I implement it on my own?
As far I know Django doesn't have such function. It's better to implement your own. With js for instance by using setInterval() and Ajax to update a specific time field.
Before that, you need to add a field to record when leaving the page.
created_on = models.DateTimeField(auto_now_add=True)
left_at = models.DateTimeField(auto_now_add=True)
Js
It's important that you have this script in your HTML page, since we'll use Django variables.
var id_obj = '{{ obj.id }}'; // $('tag').val();
totalSeconds = 5;
setInterval(function(){
recordElapsedTime();
},totalSeconds * 1000);
var recordElapsedTime = function(){
$.ajax({
url:"/url/to/view/",
type:"POST",
data:{
id_obj:id_obj,
csrfmiddlewaretoken:'{{ csrf_token }}'
},
});
}
View
import datetime
def elapsedTime(request):
if request.method == 'POST' and request.is_ajax():
id_obj = request.POST.get('id_obj')
obj = get_object_or_404(ObjectModel,id=id_obj)
obj.left_at = datetime.datetime.now()
obj.save()
Now it's pretty easy to determine the elapsed time, as a property method in Model for instance.
#property
def elapsed_time(self)
return (self.left_at - self.created_on).seconds

Django pagination while objects are being added

I've got a website that shows photos that are always being added and people are seeing duplicates between pages on the home page (last added photos)
I'm not entirely sure how to approach this problem but this is basically whats happening:
Home page displays latest 20 photos [0:20]
User scrolls (meanwhile photos are being added to the db
User loads next page (through ajax)
Page displays photos [20:40]
User sees duplicate photos because the photos added to the top of the list pushed them down into the next page
What is the best way to solve this problem? I think I need to somehow cache the queryset on the users session maybe? I don't know much about caches really so a step-by-step explanation would be invaluable
here is the function that gets a new page of images:
def get_images_paginated(query, origins, page_num):
args = None
queryset = Image.objects.all().exclude(hidden=True).exclude(tags__isnull=True)
per_page = 20
page_num = int(page_num)
if origins:
origins = [Q(origin=origin) for origin in origins]
args = reduce(operator.or_, origins)
queryset = queryset.filter(args)
if query:
images = watson.filter(queryset, query)
else:
images = watson.filter(queryset, query).order_by('-id')
amount = images.count()
images = images.prefetch_related('tags')[(per_page*page_num)-per_page:per_page*page_num]
return images, amount
the view that uses the function:
def get_images_ajax(request):
if not request.is_ajax():
return render(request, 'home.html')
query = request.POST.get('query')
origins = request.POST.getlist('origin')
page_num = request.POST.get('page')
images, amount = get_images_paginated(query, origins, page_num)
pages = int(math.ceil(amount / 20))
if int(page_num) >= pages:
last_page = True;
else:
last_page = False;
context = {
'images':images,
'last_page':last_page,
}
return render(request, '_images.html', context)
One approach you could take is to send the oldest ID that the client currently has (i.e., the ID of the last item in the list currently) in the AJAX request, and then make sure you only query older IDs.
So get_images_paginated is modified as follows:
def get_images_paginated(query, origins, page_num, last_id=None):
args = None
queryset = Image.objects.all().exclude(hidden=True).exclude(tags__isnull=True)
if last_id is not None:
queryset = queryset.filter(id__lt=last_id)
...
You would need to send the last ID in your AJAX request, and pass this from your view function to get_images_paginated:
def get_images_ajax(request):
if not request.is_ajax():
return render(request, 'home.html')
query = request.POST.get('query')
origins = request.POST.getlist('origin')
page_num = request.POST.get('page')
# Get last ID. Note you probably need to do some type casting here.
last_id = request.POST.get('last_id', None)
images, amount = get_images_paginated(query, origins, page_num, last_id)
...
As #doniyor says you should use Django's built in pagination in conjunction with this logic.