Yeah... I've Been Hiding Out...
Saturday, February 13, 2010 - 7:21 PMYea, I sort of quit blogging the last few months. Not because I don't have anything to write about or that I think it's a waste of time. Even if it was a waste of time, the real issue is I haven't had much of just that... uh, time that is. No time.
I have a list of blog post ideas in my iPhone that I just haven't had time to write them up. I also have a list of like 4 or 5 products that I think would sell really well but just no time to put them together.
Plus, I have some other business needs that are taking up most of my time right now. One of them is CartFreak, which is a "super-human" shopping cart aimed at direct response internet marketers. Check it out if you're in the market for a cart to help automate your business. You'll see the feature list compares (even beats?) most of the major carts out there.
I've also been spending a lot of time consulting with clients on marketing their websites, improving their customer retention, etc. While I love helping small businesses out, I am starting to see that it's cutting way to much into my time and it's effecting my real business goals.
So that said, here are my plans for 2010:
Restructure My Entire Business Around CartFreak
As it stands right now, CartFreak is my main focus and I want to turn it into a huge success. My partner on this project is Joe Lavery, who is an amazing marketer. This guy lives and breaths marketing. The "crazy" ideas he comes up with never stop blowing my mind... Not because their crazy, but because they WORK!
Ok, enough stroking Joe ;) We are both working really hard to help turn CartFreak into a real competitor to the larger "old" cart companies out there. We have quite a few people paying us to use the software already, and it's only in beta release. We've also had such positive feedback from big name marketers on the cart and that has been very motivating and helping us keep our focus.
Stop Consulting With Small Businesses
As much as I love helping small businesses improve their internet marketing, it's time for me to ween myself away from doing so. The reason being is that it's way to time consuming. With clients all over southern California, I find myself traveling to meet with them several times a month and each time I lose a few days in the process.
I'm still going to help out my clients, and other small businesses, just in a different fashion. I have a product in the works that will be very useful to these type of businesses and much more affordable than paying me to personally come out and meet with them so often.
Helping the "Little Guy"
Even though I, myself, am a little guy, I still have a lot to offer people new to internet marketing and process automation. I have a small, but very loyal, following and I appreciate them very much. I want to spend more of my time giving back to them - my customers!
I've got some awesome stuff in the works for them and hope to be able to start with that really soon. Note, if you want to be kept up to date on this, click here and enter your email address.
Focus on Business Automation
As a software developer, I thrive on automation. The lifeblood of my business is getting a computer to do the things that I would normally have to do. In the last year I've sort of lost track of this and honestly, been completely neglecting it. Not because of laziness, but I come back to the lack of spare time.
So I will definitely be focusing more on automating (or outsourcing) as much of my business as possible.
Do Some Software Contracting
I love writing software using Python and Django. The "geek" in me won't let it go, so assuming I can find the time I'd love to pickup some short term contracts writing software on a cool project. This wouldn't even be for the money, but more for the "fun." As odd as it sounds, writing code is almost therapeutic for me.
Write More Open Source Software
I love open source software. A lot of people don't realize this but the vast majority of internet services run on open source (FREE) software. Everything from web servers to mail servers to name servers. The very services that are the backbone of the internet, all come from people to write software and literally give it to the world.
I recently released the Zerigo DNS Python module to the open source world. I've also been submitting patches and code changes to other projects I am interested in. I want to do more of this, when I have some spare time or am in the "zone" and just want to "code"
Try To Improve My Personal Life
This is hands down the most important part of my plans for the future...
Things in my personal life have been sort of out of whack lately and I have a lot of changes coming in the very near future. Some of them are very hard for me to deal with, but like always, I will have to suck it up and move forward. Like my ARMY drill sergeants used to say - FIDO - which stands for "Fuck It, Drive On." So that's exactly what I plan on doing.
At the same time, I need to create some sort of balance. I work way to much and everything else in my life has suffered a little bit because of it. Especially my relationship with my 2 daughters. When my 10 year old tells me she doesn't get enough "quality time" with me, then something is wrong and MUST change immediately. So that's exactly what I'm doing. Making changes in the right direction.
Wrap Up
This turned into a way longer post than I planned on. Guess I had a lot of writing in me to get out ;)
Even though I will never shut down this blog, and I do want to write more here, I know I won't get to write as often as I like. Just stay subscribed (either via RSS or email) and I'll update you as things progress.
If you really wanna know what I'm up to during the day, then follow me on twitter. I update throughout the day, usually every day, there.
Here's to a great 2010!
Python / Django Goodies For eCommerce
Saturday, November 8, 2008 - 11:27 AMI should preface this post by noting that this is not for the "average" internet marketer. This is more designed for Python programmers with a love for the Django framework. Real geek stuff. If you got the stomach for it, then read on...
Serving Secure Signed Files With Expiration Times
I wrote a simple class this morning to handle secure signed Amazon S3 links with expiration times. This is very useful when you want to serve files from Amazon S3 that are part of a membership site or a digital goods purchase.
I have been serving files from my digital purchases through a custom Django view. This isn't a very strong method because for every file served (purchased) my server has to load that file into memory. I would much rather give that task to S3 since it's more reliable, very fast and so cheap that it's a no brainer.
Of course I haven't migrated this class into my payment and delivery system yet but I'll do that some time this weekend.
Django DateField To Handle Credit Card Expiration Dates
I've now built several systems for taking payment via credit card. One of the problems that consistently comes up is when a user wants to update their credit card information in the database.
Providing the interface for that is easy, but the default display for a Django DateField will display their expiration date like this:
YYYY-MM-DD
Now on your credit, or debit, cards the expiration date looks like: MM/YY. So I created a custom field to display and accept input in the MM/YY format.
Totally got rid of the customer problems when updating their account with new credit card information.
Get the code...
You can snag both snippets at my account on DjangoSnippets. They are free to use however you want. You can also see example usage of them on their individual snippet page.
Go here to download the snippets.
Technorati Tags: django, ecommerce, internet-marketing, python, snippets
Django FormWizard - Passing Data Between Forms
Friday, September 26, 2008 - 9:35 PMI recently had the need for a multi-step web form and so I wanted to give the Django FormWizard a spin because I haven't had a chance to use it yet.
The FormWizard documentation is lacking a little and it makes no mention of the support for passing an initial value for each form "step" to the Wizard. Passing an initial value is done by passing a dictionary, containing dictionaries, where the keys are the individual form step sequences. For example, the first form will have a key of 0 (zero), the second form will have a key of 1, etc. Here is an example urls.py...
# Import forms and custom wizard
from yourproject.yourapp.forms import *init = {
0: {
'field1': 'value1',
'field2': 'value2',
},
1: {
'field3': 'value3',
'field4': 'value4',
}
}# In your urlpatterns...
url(r'^wizard/$', BusinessWizard([Form1, Form2], initial=init),
This will create an instance of the BusinessWizard FormWizard (assuming that's the name of your Wizard) and it will have 2 steps, processing Form1 and Form2. When the wizard is processing the form it will pass the dictionary in key 0 to Form1 as it's initial value and it will iterate with each step.
So what happens if you need data from Form1 to be available in a field in Form2 as the initial value? Well there is no built in way to do this but the good folks over at Django decided to give us a nice helper method that is called from the __call__ method of the FormWizard class.
This helper method is called parse_params and it can be used to help us pass data to the next form by manipulating the FormWizard.initial dictionary.
One thing to note is that parse_params will be called when the form is being displayed and "written to" (via form POST). You need to check for the step PRIOR to the step where you want the data to be passed. If the request method is POST, then you can call the form and check for validation. If valid, you can assign the initial value for the next form based on the cleaned_data dictionary of the current form.
So in my case, I needed the form on step 1 (which is the second form, remember the counter starts at zero) to receive data from step 0.
Here's an example...
from django.contrib.formtools.wizard import FormWizardclass BusinessWizard(FormWizard):
def parse_params(self, request, *args, **kwargs):
current_step = self.determine_step(request, *args, **kwargs)
if request.method == 'POST' and current_step == 0:
form = self.get_form(current_step, request.POST)
if form.is_valid():
self.initial[(current_step + 1)] = {
'name': form.cleaned_data['name'],
'address': form.cleaned_data['address'],
'city': form.cleaned_data['city'],
}def done(self, request, form_list):
# Your form processing code goes here
When the second form is displayed it will have the initial value assigned in the parse_params method.
I can't think of many situations where you would want to do this but they do pop up occasionally. If you are curious about the FormWizard class check the source code out. It's a small class and very easy to follow.
Note: This might not be the "best" way to do this. The process_step method may also be a good place for this type of operation but it was called twice, conditionally, in the __call__ method so it just felt "right" to use parse_params.
Technorati Tags: django, form wizard, multi-step form, web development
Django 1.0 Released!!
Thursday, September 4, 2008 - 9:46 AMWow, Django has finally released version 1.0 of it's framework. I've been using Django for around 18 months now and have written about it many times in the past. There have many so many improvements to the framework since I started using it. If you want to create a powerful website quickly, Django is such an awesome framework to build from. Since it's pure Python it makes writing fast code such a breeze.
Anyways, I just wanted to say congrats to the entire Django team and user base. This is a big milestone for all of us.
Technorati Tags: development, django, new release, python
What Powers SmartJabber
Tuesday, April 22, 2008 - 3:31 PMI've had some inquiries to what powers SmartJabber, so I decided to write up a quick outline of the technology that is being used to power the new service.
In case you hadn't heard yet, I recently launched a new company called SmartJabber. The general idea behind the service is to offer an automated support agent via a "live chat" window. It's a cheap alternative to hiring someone to do basic live chat support.
The tool can be used to convert visitors into customers, save sales or offer a basic level of customer service (say on an FAQ page or something). There is a lot of work that goes on the back end that makes this service fast and reliable. In this geeky post, I will go over some of the technology that I used to create this tool.
Python was used for the programming on the back end. This includes the web site and back end processing. I went with Python because I love the language for a number of reasons and I have a lot of experience writing web applications using it.
Django is the ultimate web framework, written in pure Python. I began learning Django over a year ago and have worked on numerous projects using the framework since. I've created web apps using a variety of different languages and none of them can compare to the Django framework (at least in my opinion).
PostgreSQL is the most powerful and feature packed open source database system available. PostgreSQL is used to store all the records and statistics that are part of the SmartJabber service. Each chat instance is logged, with full records and tracking of user action. Because of the amount of data we store, track and process every day the database needs to be powerful enough to handle the service load. PostgreSQL should handle this just fine.
Memcached is an ultra light caching daemon that stores it's entire cache table in the server RAM. Because of this, and the access method, the results are stored, fetched and removed at a lightning fast speed. Memcached is used to store the results of some of the heavy processing that occurs often. To keep server load down, we store the results of various computations for an extended period of time.
Amazon AWS S3 is a "storage in the cloud" solution that provides super cheap data storage. The service cost is related to your direct usage. In other words, you only pay for what you actually use. Because of this policy, a lot of startups (and big companies too) use this service. We use S3 for the serving of all static media.
The actual chat window was created using Javascript combined with basic CSS usage. In other words, it's AJAX. Being that I am a Javascript weenie I hired out this aspect of the project, which was definitely a smart decision.
The entire service is run from 4 servers that handle an array of functions. While everything is designed to be highly scalable from the ground up, a lot of performance gains come from the user of S3 and Memcached. We also made sure to tune Django as much as possible to squeeze out every last drop of performance. Because Django is already pretty fast, and because of our layout, the service is very fast and if the cluster becomes a little loaded we can simply throw servers at the problem.
That's roughly the gist of it. Feel free to ask any specific questions you may have.
Technorati Tags: amazon s3, business, django, memcached, postgresql, python, smartjabber
AhCabron.com - Now Powered By Django!
Monday, October 8, 2007 - 8:52 AMAhCabron is a very NSFW website that I have worked on and off on for years. The name "Ah Cabron" (spanish) basically translates into "You Ass!". I know the owner and am more than happy to help him out when I can. I have helped with engineering and development in the past and am sort of the "go to guy" when technical issues arise. Certainly I present a bill for my services; after all... we are not Communists. <insert laughter here> (Sorry, Godfather moment..)
Little history... The site started so people can upload images of their boyfriends/girlfriends and get feedback on their looks. It was originally run using the open source coppermine gallery software. It quickly turned into people uploading adult natured images and soon it was 99% adult only content being submitted. Not one to turn away perfectly good images, the owner kept up with it.
Soon he realized that coppermine was too limited for the changes he wanted to make. That's when I entered the picture. I originally wrote a brand new system from scratch using Python and Mod Python. It was a basic system using the mod_python.publisher, mod_python.psp system for templates and my own sql wrapper for database access. For about 2 years this software has been running the site and doing a great job. It has been a bit of a hit, as it pulls in over 8M page views per month which is respectable traffic.
The time had come how ever to take the site to the next level. For that, I knew I had to rebuild this thing from scratch. Since I am now a Django groupie, I of course rebuilt the software using it. In all I would say it took me about 13 hours total to rebuild this site or about 2 weeks giving time when I had it. Most of those 13 hours was spent writing data migration scripts from the old schema to the new Django model schema. With heavy use of generic views the site was put together extremely fast. I should mention that a lot of the back end code I reused from other projects I have worked on (ex: image processing, watermarks, Amazon S3 integration, etc).
As of now the new code is basically a replication of the old site. All the old features are there and I wanted to cut that over now and flush out any bugs before I continue with the list of new features that are coming down the pipe. Video, RSS Feeds on just about anything, full user profiles and slide shows are just a few of the features on my ToDo list.
Check out the site, and pass me some feedback!
Technorati Tags: ahcabron, development, django, nsfw, python
The New Groovr!
Tuesday, August 28, 2007 - 5:29 PMAs you know, I work at Groovr. Well last night we launched the new version of the site. This includes a complete rewrite of the software that powers the site and a brand spankin' new design. The site still runs on Python + Django and was given lots more functionality. The real killer part is the iPhone app! Just head to www.groovr.com on your iPhone and you will be automatically placed in the iPhone app. Oh and we aren't done. We still have a list of features that will be slowly rolled out into the wild. You should definitely check it out!
There have been a few articles written about the new site already. Read these too!
- Mashable: Groovr Has a Circle of Trust. And iPhone Optimization.
- Paul Stamatiou: Groovr Revamped, Obligatory iPhone Interface
- TW Daily
- Summer Makeovers
- Get Your Groovr On
[Update: Added more articles above.. 8/29/2007]
Technorati Tags: django, groovr, launch, mobile, python, social network, work
Django + Flatpages = WTF?
Sunday, August 19, 2007 - 8:53 AMOK, the title is a little misleading. I love the flatpages. I recently deployed them on this blog for the about and contact pages and they were working fine. This morning I noticed that they were raising a 404 (Page Not Found) error. That's where my "WTF" in the title comes in. Here is a check list to solve this flatpage issue.
- Add the middleware and app as directed on the flatpages documentation page.
- Make sure you have the correct SITE_ID in settings.py and make sure the flatpage is assigned to that site.
- Check that you have flatpages/default.html in one of your template paths.
- Verify that your default.html template is extending the correct base template
Number 4 was my problem. I have been working on the code to allow multiple template sets to be selected in the admin interface. In doing that, I re-factored the base layout to be in template/base/base.html but the default.html was still extending base_blog.html. Doh!
I wish there was something logged somewhere though that would let me know there was an error rendering the flatpage. The 404 was pretty cryptic.
Technorati Tags: django, blog, python, 404, development
Ping Technorati from your Django App
Saturday, July 14, 2007 - 9:39 AMThere are other articles written about this, but I felt the need to write a better one. Ahem.
Meat and potatoes time.
In your settings.py file, set 2 new variables:
# 'PING' blog indexing sites.
PING_BLOG_INDEX = True# List of blog index ping URL's
BLOG_INDEX = ['http://rpc.technorati.com/rpc/ping',
'http://blogsearch.google.com/ping/RPC2',
'http://rpc.weblogs.com/RPC2']
PING_BLOG_INDEX is self explanatory. BLOG_INDEX is a list of blog XMLRPC url's that this application is going to use to notify the remote website (blog indexer) that your blog has been updated.
Let's create a new file in your blog application directory and name it ping.py. This file will hold the code that actually pings the blog indexers. Here it is:
from django.conf import settingsdef pingSites(entry, blog_name):
for site in settings.BLOG_INDEX:
try:
rpc = xmlrpclib.Server(site)
try:
p = rpc.weblogUpdates.extendedPing(blog_name,
settings.SITE_URL,
entry.get_absolute_url(),
settings.SITE_URL + '/feeds/rss2'
)
except:
# May not support extendedPing()
# Try normal ping
p = rpc.weblogUpdates.ping(blog_name,
settings.SITE_URL)if p.has_key('flerror') and p['flerror'] == True:
errlog(p['message'])
except:
errlog('pingSites: %s, exception!' % (site))
A few notes on the above code:
- errlog() is a function I have that just logs errors via syslog for my review. If you don't want to track the errors then a simple "pass" will do. I am just anal about errors and like to follow them. Heh, I said anal.
- This code assumes 2 things. One is that you have a "SITE_URL" option in your settings.py file. It should just be something like "SITE_URL = 'http://www.petersanchez.com'". And two is that your "Entry" model (the model that stores your blog posts) has a "get_absolute_url()" method. If it currently doesn't, I have to ask: What's wrong with you? Add one!
- You probably need to change the '/feeds/rss2' line to match the URL for your own RSS feed. Don't have an RSS feed on your blog yet? Write one, its super simple. Doc's are here.
Now lets edit your blogs models.py file be sure to import the pingSites() function that we just created in ping.py.
from your_project.blog.ping import pingSites
In your "Entry" model (mine is named "Entry", your mileage may vary) create a custom save() function.
def save(self):
# Save first, ping second (if configured)
super(Entry, self).save()
if settings.PING_BLOG_INDEX:
blog = Blog.objects.all()[0]
pingSites(self, blog.name)
Notes on above code:
- The 'blog' variable used in my example is because the software I wrote supports multiple blogs from a single installation. If you don't have a similar setup, just remove the "blog = Blog...." line and replace "blog.name" with the name of your blog. For example: pingSites(self, 'Joe Blow Blog')
That's it. You should be good to go. Next time you update your blog the blogosphere will immediately know about it via the blog indexers.
Technorati Tags: blog, development, django, geek, python
Oi! Update Time
Monday, July 9, 2007 - 7:22 PMBeen very busy the last few weeks. Not much time for updates here, but ill get to it soon! Here is a quick recap of the last week.
- Transformers was awesome. Not great, but pretty f'n cool.
- Django still rocks! (More tips coming soon)
- Tipping your bartender's well will result in a severe hangover. They return the love with extra strong drinks.
- Kids being gone with the grandparents for 3 weeeks is not as fun as I thought. In fact, it sucks! I miss them! It sucks even more that they don't miss me!
- In-n-Out still makes the best burgers around.
- Sunset Beach is a great place to be on a hot day.
And I'm out...
Technorati Tags: life, django, beach, burgers, transformers, hangover
