I'm writing some classes which rely heavily on **kwargs. I am wanting to write it in a manner that end users can create these objects without having to know the exact case of the keyword.
class Foo(object):
def __init__(self, **kwargs):
# Rewrite this to accept random case
if "EnableDebug" in kwargs and kwargs.get("EnableDebug") == True:
print "EnableDebug mode."
And then end-user of this library could do something this:
myobj = Foo(enableDEBUG=True)
I know I can brute force thru **kwargs and run thru a bunch of tests and string manipulation but was curious of there was a nifty trick or something I'm not aware of.
Thx for any help
Update
I'm getting an error when I try this using python 2.76:
File "/home/devel/test.py", line 144, in <dictcomp>
kwargs = {k.lower():v for k,v in kwargs}
ValueError: too many values to unpack
There's a number of ways to do this, but you could just standardize the args to lowercase and then do whatever testing you want to do:
kwargs = {k.lower():v for k,v in kwargs.items()}
Then all of your strings are guaranteed to be standardized.
Related
I have a view which should accept an end point with a query parameter, as well as without a parameter.
http://localhost:8001/v1/subjects?owner_ids=62,144
and
http://localhost:8001/v1/subjects
Here's my view file...
class SubjectPagination(JsonApiPageNumberPagination):
"""
Required for frontend to retrieve full list.
"""
max_page_size = 5000
class SubjectViewSet(Subject.get_viewset()):
pagination_class = SubjectPagination
def get_queryset(self):
import pdb; pdb.set_trace()
queryset = Subject.objects.all()
if self.request.GET['owner_ids']:
owner_id_list = self.request.GET['owner_ids'].split(',')
owner_id_list_integer = []
for i in owner_id_list:
owner_id_list_integer.append(int(i))
return queryset.filter(organization__in=owner_id_list_integer)
else:
return queryset
SubjectUserRoleViewSet = Subject.get_by_user_role_viewset(
SubjectViewSet, GroupRoleMap, Role)
I am trying to figure out how to handle both the end points? Please advice what needs to be done at the view to handle a URI with or without query strings?
Here's the urls.py
router.register(r'subjects', views.SubjectViewSet)
First of all, is a good practice to send the parameters in url-form-encode, avoiding things like that, in this case for send a list you could send id as:
?owner_ids[]=62&owner_ids[]=144
the querydict its going to be like this :
<QueryDict: {'owner_ids[]': ['62', '144']}>
and you could process it easily, like this
self.request.GET.getlist('owner_ids[]', [])
remember to use the get and get list functions of the request method GET and POST, to avoid dict errors.
Second, split returns a list the for statement in owner list id is totally unnecessary, and the queryset statement __in accept array of strings, if you actually want to convert all the items to integers use list comprehensions. For example, to convert all the items in a list to integer, just have to use:
owner_ids = [int(i) for i in owner_ids ]
this is way more fast in python and way more pythonic, and also cool too see.
and last, all urls should finish in /, even django has a settings for that called append_slash
this is what i can tell about the ambiguous question you are asking, in the next times please write questions more precisely that help people help you.
I know I can use * to force all keyword arguments to a function/method to be "named".
If I have
def abc(a, *, x=10, z=30):
pass
then the following all work
abc(5)
abc(8, x=12)
abc(9, z=31)
abc(x=17, a=4)
even if I change the function signature to def abc(a, *, x=10, y=20, z=30),
and
abc(7, 13)
throws an error.
This is extremely important because, I can use the logical place, which will help maintenance over time, without being forced to use the end position based on history.
But * is not valid in Python 2.7, and abc(a, *args, x=10, z=30) (which I tried) doesn't work either.
Is there a way to force the use of x=12 in Python 2.7? Or another way of saying: make abc(7, 13) be invalid on Python 2.7.
One way of doing this is by adding a dummy keyword argument that never gets a valid positional value (so don't check for None):
_dummy = object()
def abc(a, dummy_kw=_dummy, x=10, z=30):
if dummy_kw is not _dummy:
raise TypeError("abc() takes 1 positional argument but at least 2 were given")
That will prohibit abc(7, 13) and allow all the others. It works on Python 2 and Python 3, so it is useful when you have code that needs to run on both.
Originally I used:
def _dummy():
pass
but as #mata pointed out _dummy=object() works as well, and cleaner. Essentially any unique memory location that is not used in another way will work.
What about the following:
def abc(a, **kwargs):
# Get arguments from kwargs otherwise use default values
x = kwargs.pop('x', 10)
z = kwargs.pop('z', 30)
if not kwargs: # if kwargs is not empty
print 'extra parameters passed'
pass
This allows to force the use of kwargs and still have default values.
pop removes the key from kwargs, once you use it.
This is potentially very useful as you can check if the user gave extra parameters that do not belong to the function and in this case you can throw an error (for example).
When I want to select objects with a get() function like
personalProfile = World.objects.get(ID=personID)
If get function doesn't return find a value, a "matching query does not exist." error occurs.
If I don't need this error, I'll use try and except function
try:
personalProfile = World.objects.get(ID=personID)
except:
pass
But I think this is not the best way since I use
except:
pass
Please recommend some idea or code sample to fight with this issue
That depends on what you want to do if it doesn't exist..
Theres get_object_or_404:
Calls get() on a given model manager, but it raises Http404 instead of the model’s DoesNotExist exception.
get_object_or_404(World, ID=personID)
Which is very close to the try except code you currently do.
Otherwise theres get_or_create:
personalProfile, created = World.objects.get_or_create(ID=personID)
Although, If you choose to continue with your current approach, at least make sure the except is localised to the correct error and then do something with that as necessary
try:
personalProfile = World.objects.get(ID=personID)
except MyModel.DoesNotExist:
raise Http404("No MyModel matches the given query.")
The above try/except handle is similar to what is found in the docs for get_object_or_404...
A get_or_none() function has been proposed, multiple times now. The rejection notice is feature creep, which you might or might not agree with. The functionality is present --with slightly different semantics-- in the first() queryset method.
But first things first:
The manager throws World.DoesNotExist, a specialized subclass of ObjectDoesNotExist when a World object was not found:
try:
personalProfile = World.objects.get(ID=personID)
except World.DoesNotExist:
pass
There's also get_object_or_404() which raises a Http404 exception when the object was not found.
You can also roll your own get_or_none(). A possible implementation could be:
def get_or_none(queryset, *args, **kwargs):
try:
return queryset.get(*args, **kwargs)
except ObjectDoesNotExist:
return None
Note that this still raises MultipleObjectsReturned when more than one matching object is found. If you always want the first object regardless of any others, you can simplify using first(), which returns None when the queryset is empty:
def get_or_none(queryset, *args, **kwargs):
return queryset.filter(*args, **kwargs).first()
Note however, for this to work reliably, you need a proper order for objects, because in the presence of multiple objects first() might be non-deterministic (it probably returns the first object from the database index used to filter the query and neither indexes not the underlying tables need be sorted or even have a repeatable order).
Use both, however, only when the use of the object to retrieve is strictly optional for the further program flow. When failure to retrieve an object is an error, use get_object_or_404(). When an object should be created when it does not exist, use get_or_create(). In those cases, both are better suited to simplify program flow.
As alasdair mentioned you could use the built in first() method.
It returns the object if it exists or None if it's not
personalProfile = World.objects.filter(ID=personID).first()
I have many similar functions in my Django views.py that start off like this:
#login_required
def processMyObject(request, myObjectID, myObjectSlug=None):
logger.info("In processMyObject(myObjectID=%s, myObjectSlug=%s)" % (myObjectID, myObjectSlug))
try:
myObject = MyObject.objects.get(id=myObjectID)
except:
logger.error("Failed to get MyObject Object by ID")
raise "Failed to get MyObject Object by ID"
if myObjectSlug != None and myObject.slug != myObjectSlug:
logger.error("myObjectSlug '%s' doesn't match myObject #%s's slug" % (myObjectSlug, myObject.id))
raise "myObjectSlug '%s' doesn't match myObject #%s's slug" % (myObjectSlug, myObject.id)
Each of these functions has the same argument signature and contains the same chunk of code at the top, but then goes on to do implement some unique functionality. However this is common code in each one of them. It seems like a horrible violation of DRY for me to have typed the same code so many multiple times.
How can I use inheritance or some other technique to elegantly factor out this code so that it only appears once but is used in each of these view functions?
You can write decorator that recieves the MyObjectId and slug from view as parameter. logs the info line and raises an error if object is missing.
Just check information about function decorators and read django code for examples. For example, look up the code for the decorator you are already using (login_required) and look up the user_passes_test decorator in django.contrib.auth.decorators. That is probably the best real example for your case.
And then use the decorator in front of each view that needs it - just like you are using #login_required
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
We just now started doing the A/B testing for our Django based project. Can I get some information on best practices or useful insights about this A/B testing.
Ideally each new testing page will be differentiated with a single parameter(just like Gmail). mysite.com/?ui=2 should give a different page. So for every view I need to write a decorator to load different templates based on the 'ui' parameter value. And I dont want to hard code any template names in decorators. So how would urls.py url pattern will be?
It's useful to take a step back and abstract what A/B testing is trying to do before diving into the code. What exactly will we need to conduct a test?
A Goal that has a Condition
At least two distinct Paths to meet the Goal's Condition
A system for sending viewers down one of the Paths
A system for recording the Results of the test
With this in mind let's think about implementation.
The Goal
When we think about a Goal on the web usually we mean that a user reaches a certain page or that they complete a specific action, for example successfully registering as a user or getting to the checkout page.
In Django we could model that in a couple of ways - perhaps naively inside a view, calling a function whenever a Goal has been reached:
def checkout(request):
a_b_goal_complete(request)
...
But that doesn't help because we'll have to add that code everywhere we need it - plus if we're using any pluggable apps we'd prefer not to edit their code to add our A/B test.
How can we introduce A/B Goals without directly editing view code? What about a Middleware?
class ABMiddleware:
def process_request(self, request):
if a_b_goal_conditions_met(request):
a_b_goal_complete(request)
That would allow us to track A/B Goals anywhere on the site.
How do we know that a Goal's conditions has been met? For ease of implementation I'll suggest that we know a Goal has had it's conditions met when a user reaches a specific URL path. As a bonus we can measure this without getting our hands dirty inside a view. To go back to our example of registering a user we could say that this goal has been met when the user reaches the URL path:
/registration/complete
So we define a_b_goal_conditions_met:
a_b_goal_conditions_met(request):
return request.path == "/registration/complete":
Paths
When thinking about Paths in Django it's natural to jump to the idea of using different templates. Whether there is another way remains to be explored. In A/B testing you make small differences between two pages and measure the results. Therefore it should be a best practice to define a single base Path template from which all Paths to the Goal should extend.
How should render these templates? A decorator is probably a good start - it's a best practice in Django to include a parameter template_name to your views a decorator could alter this parameter at runtime.
#a_b
def registration(request, extra_context=None, template_name="reg/reg.html"):
...
You could see this decorator either introspecting the wrapped function and modifying the template_name argument or looking up the correct templates from somewhere (like a Model). If we didn't want to add the decorator to every function we could implement this as part of our ABMiddleware:
class ABMiddleware:
...
def process_view(self, request, view_func, view_args, view_kwargs):
if should_do_a_b_test(...) and "template_name" in view_kwargs:
# Modify the template name to one of our Path templates
view_kwargs["template_name"] = get_a_b_path_for_view(view_func)
response = view_func(view_args, view_kwargs)
return response
We'd need also need to add some way to keep track of which views have A/B tests running etc.
A system for sending viewers down a Path
In theory this is easy but there are lot of different implementations so it's not clear which one is best. We know a good system should divide users evenly down the path - Some hash method must be used - Maybe you could use the modulus of memcache counter divided by the number of Paths - maybe there is a better way.
A system for recording the Results of the Test
We need to record how many users went down what Path - we'll also need access to this information when the user reaches the goal (we need to be able to say what Path they came down to met the Condition of the Goal) - we'll use some kind of Model(s) to record the data and either Django Sessions or Cookies to persist the Path information until the user meets the Goal condition.
Closing Thoughts
I've given a lot of pseudo code for implementing A/B testing in Django - the above is by no means a complete solution but a good start towards creating a reusable framework for A/B testing in Django.
For reference you may want to look at Paul Mar's Seven Minute A/Bs on GitHub - it's the ROR version of the above!
http://github.com/paulmars/seven_minute_abs/tree/master
Update
On further reflection and investigation of Google Website Optimizer it's apparent that there are gaping holes in the above logic. By using different templates to represent Paths you break all caching on the view (or if the view is cached it will always serve the same path!). Instead, of using Paths, I would instead steal GWO terminology and use the idea of Combinations - that is one specific part of a template changing - for instance, changing the <h1> tag of a site.
The solution would involve template tags which would render down to JavaScript. When the page is loaded in the browser the JavaScript makes a request to your server which fetches one of the possible Combinations.
This way you can test multiple combinations per page while preserving caching!
Update
There still is room for template switching - say for example you introduce an entirely new homepage and want to test it's performance against the old homepage - you'd still want to use the template switching technique. The thing to keep in mind is your going to have to figure out some way to switch between X number of cached versions of the page. To do this you'd need to override the standard cached middleware to see if their is a A/B test running on the requested URL. Then it could choose the correct cached version to show!!!
Update
Using the ideas described above I've implemented a pluggable app for basic A/B testing Django. You can get it off Github:
http://github.com/johnboxall/django-ab/tree/master
If you use the GET parameters like you suggsted (?ui=2), then you shouldn't have to touch urls.py at all. Your decorator can inspect request.GET['ui'] and find what it needs.
To avoid hardcoding template names, maybe you could wrap the return value from the view function? Instead of returning the output of render_to_response, you could return a tuple of (template_name, context) and let the decorator mangle the template name. How about something like this? WARNING: I haven't tested this code
def ab_test(view):
def wrapped_view(request, *args, **kwargs):
template_name, context = view(request, *args, **kwargs)
if 'ui' in request.GET:
template_name = '%s_%s' % (template_name, request.GET['ui'])
# ie, 'folder/template.html' becomes 'folder/template.html_2'
return render_to_response(template_name, context)
return wrapped_view
This is a really basic example, but I hope it gets the idea across. You could modify several other things about the response, such as adding information to the template context. You could use those context variables to integrate with your site analytics, like Google Analytics, for example.
As a bonus, you could refactor this decorator in the future if you decide to stop using GET parameters and move to something based on cookies, etc.
Update If you already have a lot of views written, and you don't want to modify them all, you could write your own version of render_to_response.
def render_to_response(template_list, dictionary, context_instance, mimetype):
return (template_list, dictionary, context_instance, mimetype)
def ab_test(view):
from django.shortcuts import render_to_response as old_render_to_response
def wrapped_view(request, *args, **kwargs):
template_name, context, context_instance, mimetype = view(request, *args, **kwargs)
if 'ui' in request.GET:
template_name = '%s_%s' % (template_name, request.GET['ui'])
# ie, 'folder/template.html' becomes 'folder/template.html_2'
return old_render_to_response(template_name, context, context_instance=context_instance, mimetype=mimetype)
return wrapped_view
#ab_test
def my_legacy_view(request, param):
return render_to_response('mytemplate.html', {'param': param})
Justin's response is right... I recommend you vote for that one, as he was first. His approach is particularly useful if you have multiple views that need this A/B adjustment.
Note, however, that you don't need a decorator, or alterations to urls.py, if you have just a handful of views. If you left your urls.py file as is...
(r'^foo/', my.view.here),
... you can use request.GET to determine the view variant requested:
def here(request):
variant = request.GET.get('ui', some_default)
If you want to avoid hardcoding template names for the individual A/B/C/etc views, just make them a convention in your template naming scheme (as Justin's approach also recommends):
def here(request):
variant = request.GET.get('ui', some_default)
template_name = 'heretemplates/page%s.html' % variant
try:
return render_to_response(template_name)
except TemplateDoesNotExist:
return render_to_response('oops.html')
A code based on the one by Justin Voss:
def ab_test(force = None):
def _ab_test(view):
def wrapped_view(request, *args, **kwargs):
request, template_name, cont = view(request, *args, **kwargs)
if 'ui' in request.GET:
request.session['ui'] = request.GET['ui']
if 'ui' in request.session:
cont['ui'] = request.session['ui']
else:
if force is None:
cont['ui'] = '0'
else:
return redirect_to(request, force)
return direct_to_template(request, template_name, extra_context = cont)
return wrapped_view
return _ab_test
example function using the code:
#ab_test()
def index1(request):
return (request,'website/index.html', locals())
#ab_test('?ui=33')
def index2(request):
return (request,'website/index.html', locals())
What happens here:
1. The passed UI parameter is stored in the session variable
2. The same template loads every time, but a context variable {{ui}} stores the UI id (you can use it to modify the template)
3. If user enters the page without ?ui=xx then in case of index2 he's redirected to '?ui=33', in case of index1 the UI variable is set to 0.
I use 3 to redirect from the main page to Google Website Optimizer which in turn redirects back to the main page with a proper ?ui parameter.
You can also A/B test using Google Optimize. To do so you'll have to add Google Analytics to your site and then when you create a Google Optimize experiment each user will get a cookie with a different experiment variant (according to the weight for each variant). You can then extract the variant from the cookie and display various versions of your application. You can use the following snippet to extract the variant:
ga_exp = self.request.COOKIES.get("_gaexp")
parts = ga_exp.split(".")
experiments_part = ".".join(parts[2:])
experiments = experiments_part.split("!")
for experiment_str in experiments:
experiment_parts = experiment_str.split(".")
experiment_id = experiment_parts[0]
variation_id = int(experiment_parts[2])
experiment_variations[experiment_id] = variation_id
However there is a django package that integrates well with Google Optimize: https://github.com/adinhodovic/django-google-optimize/.
And here is a blog post on how to use the package and how Google Optimize works: https://hodovi.cc/blog/django-b-testing-google-optimize/.