django-paid-accounts.
A common goal in web application development goes something like this.
This is a application which makes achieving the above goals a breeze.
After you have installed it import subdomains should work on your python shell.
This application is dual licensed under the following terms.
Each license costs USD 400, and provides
Please contact licenses@uswaretech.com to buy a license.
The starting point for using this is adding subdomain.middleware.GetSubdomainMiddleware to your settings.py.
We assume that our base domain is foo.tld.
The various cases are.
You are on subdomain of your main domain www.foo.tld, this is in settings.MAIN_SITE.:
request.main_site = True
request.subdomain_text = 'www'
request.subdomain = None
You are on subdomain of your main domain bar.foo.tld, a Subdomain named bar exists in the DB.:
request.main_site = True
request.subdomain_text = 'bar'
request.subdomain = Subdomain.object.get(subdomain_text = 'bar')
You are on subdomain of your main domain baz.foo.tld, a Subdomain named baz does not exists in the DB.:
request.main_site = False
request.subdomain_text = 'baz'
request.subdomain = None
You are on another domain, www.notfoo.tld, and a Subdomain is mapped to www.notfoo.tld in the DB.:
request.main_site = False
request.subdomain_text = www.notfoo.tld
request.subdomain = Subdomain.object.get(domain = 'www.notfoo.tld')
You are on another domain, www.notfoonotbar.tld, and no Subdomain is mapped to www.notfoonotbar.tld in the DB.:
request.main_site = False
request.subdomain_text = www.notfoo.tld
request.subdomain = None
Subdomain class has attributes:
class Subdomain:
subdomain_text = models.CharField(max_length = 100, unique = True)
domain = models.CharField(null = True, blank = True, max_length = 100, unique = True)
name = models.CharField(max_length = 100)
description = models.TextField()
user = models.ForeignKey(User)
created_on = models.DateTimeField(auto_now_add = 1)
updated_on = models.DateTimeField(auto_now = 1)
For a subdomain bar.foo.tld. subdomain_text is ‘bar’, domain is None. A user has to asscociated to each Subdomain. This user should be generally treated as the owner of this subdomain.
All the arguments in the previous call are required. There are two optional arguments.
domain: eg ‘bar.notfoo.tld’. Note that this is the FQDN without the trailing dot. No http:// is required or allowed. subdomain_callback: This must be callable, which takes Subdomain as the argument. This might be used as the profile creation callback.
register_new_subdomain returns the newly created and saved subdomain.
If domain is None, return True If domain is not None, return False
Your subdomain would need some settings. Think of AUTH_PROFILE_MODULE for auth.User. So we have SUBDOMAIN_SETTINGS_MODULE in the settings.py. This setting must point to appname.ModelClass, which stores the settings for your Subdomain. The modelclass must have an attribute named subdomain as a ForeignKey to Subdomain.
Having this setting you can do something like,:
subdomain = Subdomain.objects.get(...)
subdomain.get_settings()
Just populates the objects populated into templates for ease of use. Variables populated,:
main_site
subdomain_text
subdomain
Which are the same as that populated by the middleware.
Ensure that request has a Subdomain. Eg if the url is ‘bar.foo.tld’ a Subdomain must exist with ‘subdomain_text’ of ‘bar’. With custom domains, ‘foo.notfoo.tld’ a Subdomain must exist with domain of ‘foo.notfoo.tld’. If subdomain exists, the decorated view proceeds normally.
If no Subdomain exists, the decorator redirects to reverse(‘REGISTER_SUBDOMAIN_REDIRECT’).
For example, if you access ‘notbar.foo.tld’ and a Subdomain ‘notbar’ does not exist, this will redirect to ‘notbar.foo.tld/accounts/register/’ (or something similar).
If current subdomain_text is not in settings.MAIN_SUBDOMAIN, redirects to the first Subdomain listed in settings.MAIN_SUBDOMAIN.
eg settings.MAIN_SUBDOMAIN = [‘www’, ‘mainsite’, ‘home’]
If user navigates to ‘bar.foo.tld/bit/and/pieces/’ he will be redirected to ‘www.foo.tld/bit/and/pieces/’
If user navigates to ‘www.foo.tld/bit/and/pieces/’ the view function redirects normally.
Settings with example values.:
SUBDOMAIN_SETTINGS_MODULE = 'tstsubdomains.SubdomainSettings'
BASE_DOMAIN = 'foo.tld'
REGISTER_SUBDOMAIN_REDIRECT = 'registration_register'
MAIN_SUBDOMAIN = ['www', 'mainsite', 'home']
Integrating with Paypal is very simple. There are essentially two generic views which you need to cutsomise and include.
The basic Paypal checkout pages can be created with:
#in views.py
class TestPaypalStart(PaypalStart):
def __init__(self):
super(TestPaypalStart, self).__init__()
self.template = 'tstsubdomains/paypal_start.html'
self.success_url = '/test/paypalresponse/'
self.amount = 10
class TestPaypalResponse(PaypalResponse):
def __init__(self):
super(TestPaypalResponse, self).__init__()
self.template_GET = 'tstsubdomains/paypal_response.html'
self.redirect_url_GET_success = '/'
self.redirect_url_GET_failure = '/'
self.amount = 10
And:
#in urls.py
urlpatterns = patterns('tstsubdomains.views',
url(r'^paypalstart/', TestPaypalStart(), name='test_paypalstart'),
url(r'^paypalresponse/', TestPaypalResponse(), name='test_paypalresponse'),
)
A basic Paypal site can be built with just that much code, however, these Generic views provides lots of hooks to customise it exactly to your needs. All overridable things in this generic views have the same signature:
def get_success_url(self, request, *args, **kwargs): #Or other overidable functions.
[Understanding how Paypal works would be helpful at this point. www.uswaretech.com/blog/2008/11/using-paypal-with-django/ ]
PaypalStart : This class should be overriden and used as a callable in urls.py. This maps to the initial page where you show the pay with Paypal link.
PaypalResponse: This class should be overriden and used as a callable in urls.py. This maps to to page where you show the user’s details and collect money from the user.
Though a base PaypalStart derived class can be as simple as, there are a lot of hooks for power usage.:
class TestPaypalStart(PaypalStart):
def __init__(self):
super(TestPaypalStart, self).__init__()
self.template = 'tstsubdomains/paypal_start.html'
self.success_url = '/test/paypalresponse/'
self.amount = 10
get_success_url: Overide this if you want to specify the success url, where Paypal redirects after creating a token. Default behaviour is to return self.success_url
get_failure_url: Override this if you want to specify the failure url, where Paypal redirects if user declines authorisation. Default behaviour is to return to current Url.
get_amount: Override this if you want to specify the amount. Default behaviour is to return self.amount.
get_template: Override this if you want to specify the template to use. Default behaviour is to return self.template.
process_request: Override this if you want to populate any extra variable in the template, and as a callback to do auxilarry processing. Default behaviour is to return an empty dictionary.
PaypalResponse is class which allows you to show the user’s details and do checkout on your site.
In the simplest case it can be overriden as:
class TestPaypalResponse(PaypalResponse):
def __init__(self):
super(TestPaypalResponse, self).__init__()
self.template_GET = 'tstsubdomains/paypal_response.html'
self.redirect_url_GET_success = '/'
self.redirect_url_GET_failure = '/'
self.amount = 10
The overridable hooks are:
get_template_GET: Template to render during GET.
get_redirect_url_POST_success: The Url to redirect if Paypal allows a successful checkout.
get_redirect_url_POST_failure: The Url to redirect if Paypal checkout fails.
get_amount: Amount to checkout.
process_request_GET: Callback to do extra processing during GET, when we are showing details from Paypal account. Default behaviours is to return an empty dictionary.
process_request_POST: Callback to do extra processing during POST, when we do the actual checkout. This is where we do the the actual processing, for example, generate license key, etc.
We are in the process of building a web application to demonstrate the capabilities of this web application.