I have this method on my views.py file:
def getHistoricRates():
""" Here we have the function that will retrieve the historical rates from fixer.io, since last month """
rates = {}
response = urlopen('http://data.fixer.io/api/2018-12-31?access_key=c2f5070ad78b0748111281f6475c0bdd')
data = response.read()
rdata = json.loads(data.decode(), parse_float=float)
rates_from_rdata = rdata.get('rates', {})
for rate_symbol in ['USD', 'GBP', 'HKD', 'AUD', 'JPY', 'SEK', 'NOK', 'EUR']:
try:
rates[rate_symbol] = rates_from_rdata[rate_symbol]
except KeyError:
logging.warning('rate for {} not found in rdata'.format(rate_symbol))
pass
return rates
#require_http_methods(['GET', 'POST'])
def historical(request):
date_str = "2018-12-31"
if datetime.datetime.strptime(date_str,"%Y-%m-%d").weekday()<5:
rates = getHistoricRates()
fixerio_rates = [Fixerio_rates(currency=currency, rate=rate)
for currency, rate in rates.items()]
Fixerio_rates.objects.bulk_create(fixerio_rates)
return render(request, 'historical.html')
I want to run historical at 9am every day, except for weekends.
Now, I can't find any example on how to run an existent method, or how to call it from the cron.py file whatsoever.
I do have everything configured, for django_cron but I just can't figure out how to "use" this method from my cron file to run it at specific times.
This is my cron.py file so far:
from django_cron import CronJobBase, Schedule
from .views import historical
class MyCronJob(CronJobBase):
RUN_AT_TIMES = ['9:00']
schedule = Schedule(run_at_times=RUN_AT_TIMES)
code = 'fixerio.my_cron_job' # a unique code
def do(self):
pass # do your thing here
The name fixerio is my app's name.
Any ideas on this?
Since you're looking to call the getHistoricRates() and the bulk_create() logic from both your historical() view and also a cron job, it would be better to first refactor that common code from the view into a separate module - for example into helpers.py that lives alongside the views.py and cron.py.
helpers.py
from .models import Fixerio_rates
def create_rates():
rates = getHistoricRates()
fixerio_rates = [Fixerio_rates(currency=currency, rate=rate)
for currency, rate in rates.items()]
Fixerio_rates.objects.bulk_create(fixerio_rates)
def getHistoricRates():
...
You can then invoke that from your cron job:
cron.py
from .helpers import create_rates
class MyCronJob(CronJobBase):
RUN_AT_TIMES = ['9:00']
schedule = Schedule(run_at_times=RUN_AT_TIMES)
code = 'fixerio.my_cron_job' # a unique code
def do(self):
create_rates()
And also from your view:
views.py
from .helpers import create_rates
#require_http_methods(['GET', 'POST'])
def historical(request):
date_str = "2018-12-31"
if datetime.datetime.strptime(date_str,"%Y-%m-%d").weekday()<5:
create_rates()
return render(request, 'historical.html')
Related
Im trying to add a custom action to django app, where i can redirect to a html (pdf) page i created.
currently the html page only shows 1 result, What im trying to do is to show as many as objects i selcet from the action bar in django admin. here is my code.. admin.py
def print_pdf(modelAdmin, request, queryset, **kwargs):
from django.template.loader import get_template
from django.http import HttpResponse
from django.shortcuts import render, get_object_or_404
from calculator.models import Transaction
from xhtml2pdf import pisa
chp = []
for f in queryset:
chp.append(f.chp_reference)
for q in range(len(queryset)): # here im trying to know how many times to iterate based on how many qs selected
transaction = get_object_or_404(Transaction, chp_reference=chp[1]) #im not sure what to do here
template_path = 'report-pdf.html'
context = {"transactions":transactions}
response = HttpResponse(content_type='Application/pdf')
response['Content-Disposition'] = 'filename="report.pdf'
template = get_template(template_path)
html = template.render(context)
pisa_status = pisa.CreatePDF(html, dest=response)
if pisa_status.err:
return HttpResponse('we had some errors' + html )
return response
print_pdf.short_description = 'bulk pdf'
actions = [export_csv, print_pdf]
here is my code. I know its messed up, but i been trying to figure out to do this but im lost.
help would be appreciated
What's happening is the difference between the following snipppets.
def f(x)
for i in range(x):
return i ** 2
f(5) # 0 ONLY
def f(x):
results = []
for i in range(x):
results.append(i ** 2)
return results
You're returning after the first iteration, so the loop finishes after the first iteration.
You need to do the same as the second one, collect all results and return them at the end.
To illustrate what you want, this is based on your reply here. You can use something like
transactions = Transaction.objects.none()
for pk in chp:
qs = Transaction.objects.filter(chp_reference=i)
transactions = transaction.union(qs)
return transactions
and improve it based on your needs
I am doing an app and I am using the Blueprints structure. My code is running okay, but I got this error while trying to implment flask-caching into one function.
The error returned is:
AttributeError: 'Blueprint' object has no attribute 'cache'
Does anybody has a light of solution in here to make the cache happens to this function?
Here is a piece of my code:
from flask import render_template, redirect, request, Blueprint
from cache import store_weather, number_of_views, cached_weather, cache
import json, requests
bp = Blueprint('bp', __name__, url_prefix="/weather")
main = Blueprint('main', __name__)
api_key = "42fbb2fcc79717f7601238775a679328"
#main.route('/')
def hello():
views = 5
max_views = number_of_views()
return render_template('index.html', cached_weather=cached_weather, max_views=max_views, views=views)
#bp.route('/', methods=['GET'])
def weather():
clean_list_cache()
if request.args.get('max').isdigit():
views = int(request.args.get('max'))
else:
views = 5
try:
city_name = request.args.get('city')
if city_name not in cached_weather:
uri = 'http://api.openweathermap.org/data/2.5/weather?q={city}&appid={key}'.format(city=city_name,key=api_key)
# On that point, we bring the data from the Open Weather API
rUrl = requests.get(uri)
# The temperature of the Open Weather API is in Kelvin, so, we have to subtract 273.15 to transform
# it into Celsius degrees
temperature = str(round((json.loads(rUrl.content)['main'])['temp']-273.15))+" °C"
name = json.loads(rUrl.content)['name']
description = json.loads(rUrl.content)['weather'][0]['description']
city_data = { "temp":temperature, "name":name, "desc":description }
store_weather(city_data)
max_views = number_of_views(views)
return render_template('weather.html', cached_weather = cached_weather, error_rec_city = False, max_views=max_views, views=views)
except KeyError:
max_views = number_of_views(views)
return render_template('weather.html', cached_weather=cached_weather, error_rec_city = True, max_views=max_views, views=views)
#bp.cache.cached(timeout=30, key_prefix='list_cache')
def clean_list_cache():
cached_weather.clear()
The error occurs, as you are trying to call cache on your blueprint: #bp.cache.cached. An example from the docs how to use cache is:
#app.route("/")
#cache.cached(timeout=50)
def index():
return render_template('index.html')
So you have to squeeze the cache decorator between your app decorator and the function
I have module billing/billing-collect-project-license which have LicenseStatistics class. Which have calls to Redis, ORMRDS, CE are other modules which used in this class. Following is LicenseStatistics class where get_allocate_count is instance method which calls to ce_obj.get_set_ce_obj, get_license_id and many others.
The get_license_id method calls get_customer_details.
class LicenseStatistics():
"""This class encapsulates all logic related to license usage."""
def __init__(self):
self.logger = LOGGER
# RedisNode List should be in the following format:
# HOST1:PORT1,HOST2:PORT2,HOST3:PORT3 etc
redis_node_list = os.environ.get('REDIS_NODE_LIST', '').split(',')
self.redis_utils = RedisUtils(redis_node_list)
# DB object to read customer details
dbhost = os.environ.get('DBHOST')
dbuser = os.environ.get('DBUSER')
dbpass = os.environ.get('DBPASSWORD')
dbname = os.environ.get('DBNAME')
dbport = os.environ.get('DBPORT')
self.dbutils = ORMDBUtils(dbhost, dbuser, dbpass, dbname, dbport)
self.ce_obj = CE()
self.bill = Billing()
def get_license_id(self, project_id):
"""
#Summary: Get License Id for customer/project from customer table by
project id
#param project_id (string): CE project Id
#return (string): CE License Id which associate with Project.
"""
# Get license ID from RDS
customer_details = self.get_customer_details(project_id)
print("customer_details:", customer_details)
license_id = customer_details["license_id"]
if not license_id:
msg = "No license for project {}".format(project_id)
self.logger.error(msg)
raise InvalidParamException(msg)
print("license_id:", license_id)
return license_id
def get_customer_details(self, project_id):
"""
#Summary: Get Customer/Project details from customer table
#param project_id (string): CE project Id
#return (dictionary): Customer details from customer table.
"""
filters = {"project_id": project_id}
customer_details = self.dbutils.get_items(
table_name=RDSCustomerTable.TABLE_NAME.value,
columns_to_select=["account_id", "license_id"],
filters=filters
)
if not customer_details:
msg = "No customer found for project {}".format(project_id)
self.logger.error(msg)
raise NoCustomerException(msg)
return customer_details[0]
def is_shared_license(self, license_id):
# This function return True or False
pass
def get_project_machines_count(self, project_id, license_id):
# This function return number of used license.
count = 20
return count
def get_license_usage(self, project_id, license_id):
# This function return number of machines used project.
count = 10
return count
def get_allocate_count(self, project_id):
"""
#Summary: Get number of licenses are used by Project.
#param project_id (string): CloudEndure Project Id.
#return (int): Number of license are used in Project.
"""
# set Session get_customer_detailsfrom Redis
status = self.ce_obj.get_set_ce_obj(
project_id=project_id, redis_utils=self.redis_utils
)
print("license_id status--:", status)
if not status:
msg = "Unable to set CEproject {}".format(project_id)
self.logger.critical(msg)
raise InvalidParamException(msg, "project_id", project_id)
print("project_id------------:", project_id)
# Get license Id
license_id = self.get_license_id(project_id)
print("license_id:", license_id)
# Check license is shared
shared_flag = self.is_shared_license(license_id)
if not shared_flag:
# Get license usage
licenses_used = self.get_license_usage(project_id, license_id)
else:
# Get machine account
licenses_used = self.get_project_machines_count(
project_id, license_id
)
return licenses_used
I am writing unit test for get_allocate_count method, I mock the Redis, ORMRDS, Custom Exception, Logger.
This function call ce_obj.get_set_ce_obj function which return True/False. I am to mock/patch return value of this function successfully.
But when call goes to next function call i.e. get_license_id, call goes into actual function call and due to improper inputs. I am not able to patch/mock
Following is unit test code:
import responses
import unittest
from unittest.mock import patch
import os
import sys
cwd_path = os.getcwd()
sys.path.append(cwd_path)
sys.path.append(cwd_path+"/../sam-cfns/code")
sys.path.append(cwd_path+"/../sam-cfns/code/billing")
from unit_tests.common.mocks.env_mock import ENV_VAR
from unit_tests.common.mocks.logger import FakeLogger
from unit_tests.common.mocks.cache_mock import RedisUtilsMock
from unit_tests.common.mocks.ormdb_mock import ORMDBUtilsMockProject
from unit_tests.common.mocks.exceptions_mock import NoCustomerExceptionMock
from unit_tests.common.mocks.exceptions_mock import BillingExceptionMock
from unit_tests.common.mocks.exceptions_mock import InvalidParamExceptionMock
from unit_tests.common.mocks.api_responses import mock_response
from unit_tests.common.examples import ce_machines_data
from unit_tests.common.examples import ce_license_data
from unit_tests.common.examples import ce_data
class BillingTest(unittest.TestCase):
""" Billing TEST class drive from UnitTest """
#patch("billing-collect-project-license.Logger", FakeLogger)
#patch("os.environ", ENV_VAR)
#patch("billing-collect-project-license.RedisUtils", RedisUtilsMock)
#patch("billing-collect-project-license.ORMDBUtils", ORMDBUtilsMockProject)
#patch("exceptions.NoCustomerException", NoCustomerExceptionMock)
#patch("billing.billing_exceptions.BillingException", BillingExceptionMock)
#patch("billing.billing_exceptions.InvalidParamException", InvalidParamExceptionMock)
def __init__(self, *args, **kwargs):
"""Initialization"""
super(BillingTest, self).__init__(*args, **kwargs)
billing_collect_project_license_module = (
__import__("cbr-billing-collect-project-license")
)
self.licenses_stats_obj = (
billing_collect_project_license_module.LicenseStatistics()
)
class BillingCollectProjectLicense(BillingTest):
"""Login Unit Test Cases"""
def __init__(self, *args, **kwargs):
"""Initialization"""
super(BillingCollectProjectLicense, self).__init__(*args, **kwargs)
def setUp(self):
"""Setup for all Test Cases."""
pass
##patch("billing.cbr-billing-collect-project-license.LicenseStatistics."
# "get_project_machines_count")
##patch("billing.cbr-billing-collect-project-license.LicenseStatistics."
# "get_customer_details")
##patch("billing.cbr-billing-collect-project-license.LicenseStatistics.get_license_id")
#patch("billing.cbr-billing-collect-project-license.LicenseStatistics.get_license_id")
#patch("cbr.ce.CloudEndure.get_set_ce_obj")
def test_get_allocate_count(self, get_set_ce_obj_mock, get_license_id_mock):
project_id = ce_data.CE_PROJECT_ID
license_id = ce_license_data.LICENSE_ID
get_set_ce_obj_mock.return_value = True
get_license_id_mock.return_value = license_id
# LicenseStatistics_mock.return_value.get_license_id.return_value = license_id
#get_license_id_mock.return_value = license_id
# self.licenses_stats_obj.get_license_id = get_license_id_mock
get_customer_details_mock = {"license_id": license_id}
# is_shared_license_mock.return_value = True
# get_project_machines_count_mock.return_value = 20
resp = self.licenses_stats_obj.get_allocate_count(
project_id
)
self.assertEqual(resp, 20)
if __name__ == '__main__':
unittest.main()
I am not able to patch get_license_id function from same class. This actually calling get_license_id function and fails.
I want to mock return value of get_license_id function.
Anyone help help me?
Thank you.
Issue is I am initializing it in the init, so monkeypatching methods of LicenseStatistics class later have no effect on the already created instance. #hoefling
By monkey Patching I able to run Test Cases successfully.
sample code:
def test_get_allocate_count_ok_4(self, ):
"""
#Summary: Test case for successful response for shared license
by other unittest method - Monkey Patching
"""
def get_customer_details_mp(_):
"""Monkey Patching function for get_customer_details"""
data = [
{
"account_id": "abc",
"project_id": "abc",
"license_id": "abc",
"status": "Active"
}
]
return data
def get_set_ce_obj_mp(_, _tmp):
"""Monkey Patching function for get_set_ce_obj"""
return True
def get_license_id_mp(_):
"""Monkey Patching function for get_license_id"""
return "abc"
def is_shared_license_mp(_):
"""Monkey Patching function for is_shared_license"""
return True
def get_project_machines_count_mp(_, _license_id):
"""Monkey Patching function for get_project_machines_count"""
return 5
project_id = "abc"
# Monkey Patching
self.licenses_stats_obj.get_customer_details = get_customer_details_mp
self.licenses_stats_obj.ce_obj.get_set_ce_obj = get_set_ce_obj_mp
self.licenses_stats_obj.get_license_id = get_license_id_mp
self.licenses_stats_obj.is_shared_license = is_shared_license_mp
self.licenses_stats_obj.get_project_machines_count = (
get_project_machines_count_mp
)
resp = self.licenses_stats_obj.get_allocate_count(project_id)
self.assertEqual(resp, 5)
I have lots of simple Django views that look like this:
#team_leader_required
def view_all_teams(request):
teams = Team.objects.all()
template_vars = {'toolbar': 'teams',
'teams': teams}
return render(request, "all_teams.html", template_vars)
I end up writing lots of unit tests of the form:
def test_view_all_teams_renders(self):
user = self.create_team_leader()
self.log_in(user)
response = self.client.get(reverse('all_teams'))
self.assertHttp200(response)
Despite my convenience methods for creating users (e.g. .create_team_leader) and various convenience assertions (e.g. .assertHttp200), I still end up with a lot of duplication in my tests.
(My tests are simple since I can't see anything else useful to assert about these views -- TestCase.assertTemplateUsed breaks if you rename templates, even if the view is correct.)
It's easy to miss a test, which gives me little confidence when I rename templates. Is there any way I can automatically generate test cases? Something like (psuedo-code):
for every view in urls:
if view doesn't take extra arguments:
test that view returns 200 when a logged in superuser does a GET
EDIT
Here's a representative snippet from my urls.py:
urlpatterns = patterns('',
url(r'^teams/$', 'teams.views.view_all_teams', name='all_teams'),
url(r'^teams/major/$', 'teams.views.view_major_teams', name='major_teams'),
url(r'^teams/minor/$', 'teams.views.view_minor_teams', name='minor_teams'),
url(r'^teams/(?P<team_id>\d+)/$', 'teams.views.view_team', name='view_team'),
url(r'^teams/(?P<team_id>\d+)/edit$', 'teams.views.edit_team', name='edit_team'),
url(r'^teams/(?P<team_id>\d+)/delete$', 'teams.views.delete_team', name='delete_team'),
I'd like to automatically test the first three views in this list.
from django.core import urlresolvers
from django.test import TestCase
class SimpleTest(TestCase):
def test_simple_views(self):
url_names = [
'all_teams',
'major_teams',
'minor_teams',
'view_team',
'edit_team',
]
user = self.create_team_leader()
self.log_in(user)
for url_name in url_names:
try:
url = urlresolvers.reverse(url_name, args=(), kwargs={})
except urlresolvers.NoReverseMatch:
#print('Pass {}'.format(url_name))
continue
#print('Try {}'.format(url_name))
response = self.client.get(url)
self.assertHttp200(response)
If all url patterns have their name, You can use follow code to define url_names:
url_names = [p.name for p in teams.urls.urlpatterns]
Known Issues
If view function fail, you will not know which view failed.
Views next to failed view will not be tested.
Another version that handle above issues.
import unittest
from django.core import urlresolvers
from django.test import TestCase
from teams.urls import urlpatterns
class SimpleTest(TestCase):
...
def setUp(self):
user = self.create_team_leader()
self.log_in(user)
url_names = [p.name for p in urlpatterns]
vs = vars()
def make_test_function(idx, url_name, url):
def t(self):
response = self.client.get(url)
self.assertHttp200(response)
t.__name__ = 'test_' + idx
t.__doc__ = 'simple get test for ' + url_name
return t
for i, url_name in enumerate(url_names):
i = str(i)
try:
url = urlresolvers.reverse(url_name, args=(), kwargs={})
vs['test_' + i] = make_test_function(i, url_name, url)
except urlresolvers.NoReverseMatch as e:
vs['test_' + i] = unittest.skip(url_name + ' requires parameter(s) or view not found')(lambda: 0)
del url_names, vs, make_test_function,
I am having a hard time with tests in Django and Python, for my final project I am making a forums website, but I don't really have any idea how or what my tests should be. Here is the views page from mysite file. Could someone please walk me through what I should test for besides if a user is logged in.
from django.core.urlresolvers import reverse
from settings import MEDIA_ROOT, MEDIA_URL
from django.shortcuts import redirect, render_to_response
from django.template import loader, Context, RequestContext
from mysite2.forum.models import *
def list_forums(request):
"""Main listing."""
forums = Forum.objects.all()
return render_to_response("forum/list_forums.html", {"forums":forums}, context_instance=RequestContext(request))
def mk_paginator(request, items, num_items):
"""Create and return a paginator."""
paginator = Paginator(items, num_items)
try: page = int(request.GET.get("page", '1'))
except ValueError: page = 1
try:
items = paginator.page(page)
except (InvalidPage, EmptyPage):
items = paginator.page(paginator.num_pages)
return items
def list_threads(request, forum_slug):
"""Listing of threads in a forum."""
threads = Thread.objects.filter(forum__slug=forum_slug).order_by("-created")
threads = mk_paginator(request, threads, 20)
template_data = {'threads': threads}
return render_to_response("forum/list_threads.html", template_data, context_instance=RequestContext(request))
def list_posts(request, forum_slug, thread_slug):
"""Listing of posts in a thread."""
posts = Post.objects.filter(thread__slug=thread_slug, thread__forum__slug=forum_slug).order_by("created")
posts = mk_paginator(request, posts, 15)
thread = Thread.objects.get(slug=thread_slug)
template_data = {'posts': posts, 'thread' : thread}
return render_to_response("forum/list_posts.html", template_data, context_instance=RequestContext(request))
def post(request, ptype, pk):
"""Display a post form."""
action = reverse("mysite2.forum.views.%s" % ptype, args=[pk])
if ptype == "new_thread":
title = "Start New Topic"
subject = ''
elif ptype == "reply":
title = "Reply"
subject = "Re: " + Thread.objects.get(pk=pk).title
template_data = {'action': action, 'title' : title, 'subject' : subject}
return render_to_response("forum/post.html", template_data, context_instance=RequestContext(request))
def new_thread(request, pk):
"""Start a new thread."""
p = request.POST
if p["subject"] and p["body"]:
forum = Forum.objects.get(pk=pk)
thread = Thread.objects.create(forum=forum, title=p["subject"], creator=request.user)
Post.objects.create(thread=thread, title=p["subject"], body=p["body"], creator=request.user)
return HttpResponseRedirect(reverse("dbe.forum.views.forum", args=[pk]))
def reply(request, pk):
"""Reply to a thread."""
p = request.POST
if p["body"]:
thread = Thread.objects.get(pk=pk)
post = Post.objects.create(thread=thread, title=p["subject"], body=p["body"],
creator=request.user)
return HttpResponseRedirect(reverse("dbe.forum.views.thread", args=[pk]) + "?page=last")
First read the Django testing documentation. You might also want to read this book. It's dated in some areas, but testing is still pretty much the same now as it was in 1.1.
It's a bit much of a topic to cover in an SO answer.
Well, you could test:
If you have the right number of pages for the objects you're paginating.
If the page you're viewing contains the right object range. If trying to access a page that doesn't exist returns the
appropriate error.
If your views for listing objects and object detail return the correct HTTP status code (200)
For starters. Hope that helps you out.