A/B Testing using Django
When I make any change on my web page, I always wonder if this change affects the user experience. Here I will be sharing my thoughts on A/B Testing using Django, which I often use in these scenarios before finalizing any change. However, Online training on Python can help you understand the concepts mentioned below.
What is Django?
Django is a framework used for web development. It is written in Python. It is a free and open-source tool. It is a complete tool for a web developer. It can work with any framework used on the client side. It provides an output in almost all possible formats like HTML, JSON, XML, etc.
It is a secured framework. It can store the session information in the database instead of keeping it in the cookie. It saves the password hash instead of directly holding the password. We can easily add hardware at any level of the architecture to manage higher traffic to the website.
The code written in Django is reusable and easy to maintain. As the code is written in Python, it can be used on several platforms like Windows, Linux, Mac, etc.
What is A/B Testing?
Bucket testing or split testing are alternative names for A/B Testing. It is a method by which the developer verifies different versions of the web page or software application. During these experiments, other users will be using different versions of the web page and based on their response, corrective actions, if needed, are taken.
During this analysis, direct questions related to change are asked for which data is collected. This data set is considered to study the impact.
Why is A/B Testing used?
When a user visits or page for different reasons, they are lost a couple of times trying to find the right button to click or find the demo button, and so on. This results in a loss of interest for the visitor, and conversion doesn’t happen. As a result, this or ROI is impacted. So with A/B testing, we can improve our ROI with a better customer experience. Due to the exception mismatch, or many other reasons, the bounce rate may be high for our website. This can be reduced using A/B testing, and our customers can spend more time on our website.
A/B Testing will also prevent you from making significant modifications that can impact the ROI. In such a case, you can make smaller improvements to test its usability, and if it works fine, go ahead with other small modifications. The entire change is done in steps saving any trouble that could have been caused due to the significant modification done at once. It is a statistical method used to judge who the winner is and who the loser is. This is full-proof testing of your website to give you better performance and user experience.
Want to Upskill to get ahead in your career? Check out the Python Training in Pune.
Working principle of A/B testing?
The users trying to access the page is divided into two user groups. In this testing, one set of users will be directed to the original web page. While the other set of users are referred to the updated version of the web page.
The next step is to analyze the activities done by the different sets of users on their respective pages. The critical data thus obtained is used to understand how useful the web page is for the user.
Steps that are taken for A/B testing using Django
- We divide our set of users into different buckets. We assign a bucket number starting from 1 to 150. Any random number can be chosen as per our needs. The higher the value, the more users test the performance of the page. This will give better results that can be used for further analysis.
- We need to define two constants, the first being the view through which the user is routed. And the other being specifies the primary view.
- The tuple for the first constant will contain the range of the users of one bucket.
- The main view in the second constant will be used only when we do not want anonymous users been included for A/B testing.
AB_TEST = {
tuple(xrange(1,75)): demo_app.views.view_a’,
tuple(xrange(75,150)): demo_app.views.view_b’,
}
AB_TEST_PRIMARY = demo_app.views.view_a’
5. Two decorators are then written to wrap each view. The first decorator will handle the view while the other will take the template.
6. The decorator would take the first constant that we defined as a dictionary view. It will also take the primary view, which is specified by the second constant. Along with this, it accepts a Boolean value that will determine if the anonymous users are included in A/B testing or not.
The function of decorator for any user that has logged in
v It will check what is the bucket number for the user
v It will also check which view is assigned to the user
After all these checks, it will return the corresponding view for the user.
However, in the case of an anonymous user who is not included in the testing, a primary view is returned.
In case if we want to include the anonymous user in the testing, we will need to,
v Assign a unique cookie to the user, which does not depend on the session.
v A fast and straightforward key-value pair is stored like Redis.
After making these settings then we need to take the below actions
v Get the unique cookie of the user.
v Validate if the key is present in Redis for the value of the cookie.
v If Redis returns a value, select the appropriate view.
v If Redis does not return a value, then choose a random view from the view dictionary.
v Now assign the corresponding user for the particular key along with the amount of the view.
v Now return the appropriate view satisfying the above conditions.
Using this strategy, the anonymous user will be included for A/B Testing, and the corresponding view will be allocated to it throughout the testing cycle.
Now let us consider code for a decorator that we can use for A/B Testing.
“””
Decorator to A/B test different views.
Args:
primary_view: Fallback view.
anonymous_sticky: Determines whether A/B testing should be performed on
anonymous users as well.
view_dict: Dictionary for views that contains the buckets as keys.
“””
def ab_views(
primary_view=None,
anonymous _sticky=False,
view_dict={}):
def decorator(f):
@wraps(f)
def _ab_views(request, *args, **kwargs):
# This is the block of code where you may write anything that needs to be done # on the view
# ctx = f(request, *args, **kwargs)
view = None
try:
if user_is_logged_in():
view = _get_view(request, f, view_dict, primary_view)
else:
redis = initialize_redis_obj()
view = _get_view_anonymous(request, redis, f, view_dict,
primary_view, anonymous _sticky)
except:
view = primary_view
view = str_to_func(view)
return view(request, *args, **kwargs)
def _get_view(request, f, view_dict, primary_view):
bucket = get_user_bucket(request)
view = get_view_for_bucket(bucket)
return view
def _get_view_anonymous(request, redis, f, view_dict,
primary_view, anonymous _sticky):
view = None
if anonymous _sticky:
cookie = get_cookie_from_request(request)
if cookie:
view = get_value_from_redis(cookie)
else:
view = random.choice(view_dict.values())
set_cookie_value_in_redis(cookie)
else:
view = primary_view
return view
return _ab_views
return decorator
Now let us break the entire code and understand them.
7. If we have a regular user, it will first check whether the user is logged in or not. If logged in, it will return the view by checking in the view dictionary in the _get_view function().
def _get_view(request, f, view_dict, primary_view):
bucket = get_user_bucket(request)
view = get_view_for_bucket(bucket)
return view
8. If an anonymous user is logged in, it will check if the anonymous_sticky flag is true or false. If correct, it will check for the corresponding value for Redis’s view, depending on the cookie value that is returned. Otherwise, it will return a random view and set the cookie value in Redis.
If the anonymous_sticky flag is False, then it will return the primary view.
def _get_view_anonymous(request, redis, f, view_dict,
primary_view, anonymous _sticky):
view = None
if anonymous _sticky:
cookie = get_cookie_from_request(request)
if cookie:
view = get_value_from_redis(cookie)
else:
view = random.choice(view_dict.values())
set_cookie_value_in_redis(cookie)
else:
view = primary_view
return view
9. We also need to understand the code for the function str_to_fun(func_string). This function is used to return a view object based on the path of view.
def str_to_func (func_string):
func = None
func_string_splitted = func_string.split(‘.’)
module_name = ‘.’.join(func_string_splitted[:-1])
function_name = func_string_splitted[-1]
module = import_module(module_name)
if module and function_name:
func = getattr(module, function_name)
return func
This function will split the function using the “.” operator. and store it in the array function_string_splitted. It then segregates the module name and function name from it. It then gets the view object based on the function and module name and returns the view shown to the user.
We can do A/B testing on templates as well. This can be achieved by replacing the view dictionary with a template dictionary and returning a template.
Putting the views together
Let us call view A as view_a and view B as view_b, which are to be tested. Now let us write a new view view_ab. We will wrap this new view_ab with one of the decorators we used in the above code and create a unique URL pointing to this new view.
@ab_views(
primary_view=AB_TEST_PRIMARY,
anonymous_sticky=True,
view_dict=AB_TEST,
)
def view_ab(request):
ctx = {}
return ctx
Now from the above-written code, we can understand that the primary view is the new primary view AB_TEST_PRIMARY. Also, here, this piece of code is tested for anonymous users as well. Here, in this case, the modern view is returning to the dictionary.
Now the last thing we need to do is integrate the framework with analytics. This will help us in understanding which view performs better. You may use any tracking or analytics tool to evaluate the performance. However, we have used Mixedpanel to track the behaviour of the users.
To do this experiment with A/B/C testing, the only change would be needed in the AB_TEST constant that has been used in the above code.
Looking forward to becoming a Python Developer? Then get certified with 3RI Technologies.
How to set up A/B testing in a Django web application?
-
Set the Stage: Django Waffle
A Django framework for AB testing is called Django-Experiments. Waffle is a feature-flipped Django module that strives to be clear-cut, compatible with both the Django/Jingo/Jinja2 stack that we use at Mozilla and Django templates right out of the box.
Django Waffle is a Django feature flipper that needs to be installed first. We can test and manage which consumers see which iteration of a feature by specifying numerous iterations using Waffle. Additionally, it gives us switches and flags that we can use for A/B testing.
- Use pip to install Django Waffle:
pip install waffle django
- Open your settings and add “waffle” to the list of installed apps (INSTALLED_APPS).
-
Creating Flags
With Waffle, you may provide a variety of justifications for why a request should have a flag raised. For instance, you can configure flags to be active for all authenticated users or superusers. You can also select which subset of “everyone else” will see the flag as active.
Create an A/B test flag together. We’ll complete this on the Django admin website.
Once a user sets a flag, it applies to all requests and page visits; flags are global. Flags can be used to hide specific views, templates, or even entire views.
Waffle allows flags to be activated based on the query string, so you can be certain that a flag will be enabled or disabled for each request for testing.
import Flag from waffle.models
# Create a new flag.
Banner.flag = objects.Create a flag with the text “new feature,” the percentage “50.0,” and the None setting on it.save()
The marker ‘new_feature’ is active for 50% of users (percent=’50.0′). Not everyone is impacted because everyone has a value of None.
-
Implementing the Feature
Before configuring django-experiments, confirm that your redis server is up and running.
Let’s do some A/B testing with a simple view to demonstrate. In this example, we will assess two versions of a homepage.
waffle_flag is imported from waffle.decorators
@waffle_flag define homepage(request) ‘new_feature’: render(‘new_homepage.html’, request) in return
in function homepage(request), return render(request, ‘old_homepage.html’)
Upon accessing the homepage, Django Waffle checks to see if the user has activated the new_feature flag. If such is the case, the user sees the new_homepage.html template. If not, the user sees the old_homepage.html template.
- Logging and Analyzing
The first step to getting insight into the inner workings of your apps and infrastructure is to have logging that is dependable and efficient.
Although Django is one of the most popular Python web application frameworks, it isn’t practical to manually manage and analyse large Django log files because this may be very time-consuming and difficult to scale with the rest of your organization’s operations.
To gauge the performance of each iteration of your feature, you’ll need to set up logging. Here, Django’s integrated logging can be useful.
import logging
logging.getLogger(__name__) = logger
‘new_feature’, @waffle_flag
logger.info(‘Viewed the new homepage’) is the function homepage(request).
render(request) and return ‘new_homepage.html’
logger.info(‘Viewed the old homepage’) def homepage(request)
render(‘old_homepage.html’, request) in return
Every time a version of the homepage is seen, a message is recorded. Later on, you can examine these logs to determine the number of times each version was viewed.
But you should take other metrics into account besides views. Measuring conversions—that is, the number of people who viewed the page and completed the intended action—is frequently more significant. This will largely depend on your application, but in order to track these actions, you’ll need to include the necessary logs.
What should we take care of while doing A/B Testing?
- If someone says this payment gateway works for them, you assume that it can work for you. If you don’t include that in your testing, it may give wrong results. So it would help if you had all possible cases after thorough research.
- Even while undergoing the test rounds, you feel that it might give failed results. Don’t get discouraged. Continue with the test. The results might give you some other statistical insights which might be helpful in some different scenarios.
- It would help if you took care that the duration of testing is significantly long that traffic to both users’ set is acceptable. Also, if the test is run for a short period or an extended period, it may give incorrect results. So the time factor should depend upon the existing traffic and conversion rate.
- A failed test run should be used as a foundation for changes that need to be done for the next round of A/B testing.
To understand Django better, I would suggest you enroll in Full Stack Course in Pune. 3RI Technologies is a well-known institute that offers a holistically designed online course on Python. It is ISO 9001:2015 certified company providing training in different technology in IT.
They have a well-curated syllabus to cover all the concepts that are in demand in today’s industry. The trainers at their institutes have working experience of 8+ years as Python expert in IT companies. Also, their focus is on hands-on training. The institute’s programs make all candidates job-ready, making it easier for them to get absorbed immediately after the course completion.
They provide placement assistance with their tie-ups with 300+ software companies across India. They have 1000+ students already placed through them and now working successfully in their new careers. They also provide help in preparing Resumes. They also conduct practice interview rounds. They also share the most commonly asked interview questions, which increase our chance of performing better in interviews in various companies. We can also attend their Personality development workshops to improve our soft skills as part of this Online Training on Python.
At the end of the Python online training, you will also be awarded Python Online Course certification recognized by almost all industries.
3RI Technologies also provide Python Training in Noida
Python Training Offered In Different Locations are