Pragmatically adding give-aways/freebies to an online store - python

Our business currently has an online store and recently we've been offering free specials to our customers. Right now, we simply display the special and give the buyer a notice stating we will add the extra free items to their order after they checkout. Of course, it'd be nice to automate this entire process.
I've been mulling over a few ideas, mainly creating a Discount model (I'm using Django in this case, but this is more of a logic question) and having that model have a variety of flags and product lists so I could create an instance like so:
Discount(
description="Get one free pair of bands when you buy two pairs of shoes.",
valid_products=[BigProductA, BigProductB],
received_products=[FreebieProductA, FreebieProductB],
special_in_intervals=2, # Whenever the user buys 2, give one for free
)
This logic kind of works. I can then take a look at what is in their cart and test against the existing Discounts in the model and see if they apply for anything. The biggest problem with this is it can get very messy especially if you have multiple specials going on and I just don't see it working out too well.
Unfortunately, that's really my best idea for this right now. So, I come to ask you guys: What do you think is the best approach for this? I'm not looking for code, just some ideas of logic and ways to do this. :)
Thanks in advance!

Welcome to hell. Stay a while. ;) Ahem.
Discounts are a mess, so it's not surprising that you feel tainted by having to work with them. From a design point of view, the testing should be part of the Discount instance, i.e. there should be an appliesTo(cart) method and an apply(cart) method. The first tells you whether a discount applies, the second one actually applies the discount. I suggest that the apply() method doesn't change the "user part" of the cart but instead modifies extra fields, so you can easily reset the cart (drop all discounts) and run the process again.
This way, you can cleanly implement the two types of discounts that appear most often: "Get X for free, when buying Y" and "get a rebate of X% if you buy for Y $$$". Since you don't change the original figures, you can easily apply multiple discounts and rebates.
I also suggest to back this up with a whole lot of unit tests to make sure the whole thing behaves as you expect. Otherwise the next discount might be your last. :)

I don't quiet get the question - but if you select DISTINCT (I'm writing "pseudo logic" in SQL) all free items that match the items in the car , and then if you wish to give only one or n of them -
SELECT TOP(n) DISTINCT from tblFREE where freebeid in (select freebdid from tbl itemsfreebe where items in (Select Items from CART where **** Freebe givaway LOGIC***))
freebe giveaway logic is the generic placeholder that should always evaluate for true or false:
like where (select count(*) from cart >2)
so if the logic works - you'll get items in the list, and if not - you'll get nothing.
you can move this logic to your code and run only the first part of the "query" in the DB...
logic can be used with AND or OR with other logics....
once the user accept the offer - you add the list to the cart, and should rais a flag that the discount/freebee was applied - so it won't happen twice...
I wonder what does it means that it easier to SQL it than to say it :-)
I hope that targets your question...

Related

Separate Database table vs serialized key:value pair

I am working on designing a relational database for a meal scheduler web application.
I have it 99% set up, but I am wondering if to use a separate table for the "meal type" entries.
To sum it up, users can add their own meal type(breakfast, snack, dinner) arbitrarily, in any order, and I am currently storing them in a simple list (ordered with javascript in the frontend for convenience).
It won't have more than half a dozen elements at worst (who even plans more than 6 meals a day anyway), so I am saving it all in the database's settings table, which contains rows as key:value pairs.
In this case, it's 'meals': [json string representing the python list]
The problem is that every scheduled recipe needs to be qualified by meal type.
id_scheduled_meal
id_recipe
meal_type
Right now, I'd have to use the exact string saved in the key:value pair in order to associate it with a specific meal type, so meal_type would be "Breakfast" or "Snack", rather than an id. It feels like too much redundant data.
At the same time, I am not sure it would be good to create a separate object (Meal) with a separate table (meal), only to add 4-6 entries and 1-3 columns (id, name, position).
Any suggestions? I am happy to clarify, I realize the explanation might not be as clear as it could.
Thanks in advance
I feel like this is pretty opinion based, and the answer will depend on how you want to interact with the data. If you plan on writing queries that include the meal type, then you might save yourself some pain and just do the extra table, though managing/saving items will be more complex. If it's just a list that you plan on doing everything with in python (or whatever), then serialising a list and saving the text might be the better choice. Whether the extra redundant space will adversely affect you will depend on your application and requirements.

Building dynamic SQL queries with psycopg2 and postgresql

I'm not really sure the best way to go about this or if i'm just asking for a life that's easier than it should be. I have a backend for a web application and I like to write all of the queries in raw SQL. For instance getting a specific user profile, or a number of users I have a query like this:
SELECT accounts.id,
accounts.username,
accounts.is_brony,
WHERE accounts.id IN %(ids)s;
This is really nice because I can get one user profile, or many user profiles with the same query. Now my real query is actually almost 50 lines long. It has a lot of joins and other conditions for this profile.
Lets say I want to get all of the same information from a user profile but instead of getting a specific user ID i want to get a single random user? I don't think it makes sense to copy and paste 50 lines of code just to modify two lines at the end.
SELECT accounts.id,
accounts.username,
accounts.is_brony,
ORDER BY Random()
LIMIT 1;
Is there some way to use some sort of inheritance in building queries, so that at the end I can modify a couple of conditions while keeping the core similarities the same?
I'm sure I could manage it by concatenating strings and such, but I was curious if there's a more widely accepted method for approaching such a situation. Google has failed me.
The canonical answer is to create a view and use that with different WHERE and ORDER BY clauses in queries.
But, depending on your query and your tables, that might not be a good solution for your special case.
A query that is blazingly fast with WHERE accounts.id IN (1, 2, 3) might perform abysmally with ORDER BY random() LIMIT 1. In that case you'll have to come up with a different query for the second requirement.

Big mysql query versus an http post connection in terms of long term speed

right now I think i'm stuck between two main choices for grabbing a user's friends list.
The first is a direct connection with facebook, and the pulling the friends list out and creating a list of friend models with the json. (Takes quite a while whenever I try it out, like 2 seconds?)
The other is whenever a user logs in, the program will store his or her entire friends list inside a big friends model (note that even if two people have the same exact friends, two sets will still be stored, all friend models will have an FK back to the person who has these friends on their list).
Whenever a user needs his or her friends list, I just use django's filter to grab them.
Right now this is pretty fast but that's because it hasn't been tested with many people yet.
Based off of your guys experience, which of these two decisions would make the most sense long term?
Thank you
It depends a lot on what you plan on doing with the data. However, thinking long term you're going to have much more flexibility with breaking out the friends into distinct units than just storing them all together.
If the friend creation process is taking too long, you should consider off-loading it to a separate process that can finish it in the background, using something like Celery.

How to find objects where the key is NOT in a StringListProperty in GoogleAppEngine

I'm pretty sure the above is NOT directly possible (but I would be happy to be wrong). So here is what I am trying to do, but I can't figure out how to do get a useful query to work.
class Challenge(db.Model):
name = db.StringProperty()
players = db.StringListProperty(default=[])
created_on = db.DateTimeProperty(auto_now_add=True)
completed_on = db.DateTimeProperty(default=None)
There can be thousands of challenges. You can join any number of challenges at any time (prior to it being 'completed', but you can only join any challenge one time.
edit-----------------------------
Challenges are completed asynchronously (they can last multiple days) and a "winner" is decided at the end of that period, so people might be in several challenges at the same time, waiting for those challenges to end. Basically, you join a challenge and complete the task, then wait for others to do the same, then the winner is chosen when the challenge comes to a end. While you are waiting, you can join and complete other challenges. There is a limit of 250-500 people per challenge (haven't decided on the max yet)
------------------------------edit
I want to make a list of all the challenges you CAN join, ordered by created_on. players is a list of str(user.key()) for all those that have joined a challenge.
You could do it something like:
already_in = Challenge.all().filter('players = ', str(self.user.key())).filter('completed_on =', None)
already_in_set = set()
for challenge in already_in.fetch(1000):
already_in_set.add(str(challenge.key())) # Could cache this in the user object
challenges = Challenge.all().order('created_on')
keepers = []
for challenge in challenges:
if str(challenge.key()) not in already_in_set:
keepers.append(challenge)
if len(keepers) > 11:
break
and now keepers has the list of the ones you aren't in. But the above code doesn't feel very optimal.
Surely there is another way to do this. (I'm not against restructuring the db to make it work better either)
I could cache the already_in_set as a StringListPropery(indexed=False) on the User object and that would provide some speed up, but then I'd have to prune that to remove Challenges that are now completed (which I could do outside the UI request).
I'm hoping I'm missing something obvious about how to use the AppEngine datastore to do the query.
As you guessed, this isn't really possible. Elements in list properties are indexed individually, so a filter for "not equal to x" would return any list that has at least one value not equal to x, not the desired result.
Given the situation you describe, though, it seems unlikely that users will be in an unbounded number of challenges. Fetching the challenges they're already in, and filtering those results out of result sets, seems like a reasonable solution. If you want to make things more efficient, you could store the list of challenges against the user instead of vice-versa. This also means there's no longer a practical limit on how many users can participate in a given challenge.
Finally, don't use a db.StringListProperty to store serialized keys - instead, use a db.ListProperty(db.Key).
Given the constraint that a user can only join one challenge at a time, if you record the non-completed challenge (if any) that a user is participating in, you can retrieve that very efficiently. Then (if I understand you correctly) one of two cases apply: Either the user is participating in a Challenge already, in which case no query on Challenge is needed, or you do need to query for available challenges. To do the latter query, it might help to also store a completed flag in the Challenge.
This means you'll have to do a bit of additional bookkeeping when a Challenge is completed, finding all participating Users and voiding their participation.

Django shopping cart/basket solution (or should I DIM)?

I'm about to build a site that has about half a dozen fairly similar products. They're all DVDs so they fit into a very "fixed" database very well. I was going to make a DVD model. Tag them up. All very simple. All very easy.
But we need to be able to sell them. The current site outsources the whole purchasing system but that's not going to fly on the new site. We want to integrate everything right up until the payment (for both UX reasons plus we get to customise the process a lot more).
The other problem with the outsourced problem is it doesn't account for people that don't need to pay VAT (sales tax) or for the fact you get a discounts if you buy more than one of the same thing, or more than one SKU at the same time.
So I've been looking around.
Satchmo looks like a whole mini-framework. It has listing options that I just don't need with the quantities of SKUs I'm dealing with.
django-cart has been re-hashed as of March but it looks pretty abandoned since then.
I'm looking for something that will let me:
pass it a model instances, a price and a quantity
apply a quantities formula based on the number of unique SKUs and copies in the same title
list what's in the cart on every page
That's about it (but it's quite fiddly, nevertheless). I can handle the final order processing nonsense.
Or am I just being silly?
Should I just get on and Do It Myself? If that's your vote, I've never built a cart before so are there any considerations that are not obvious to somebody who has only used shopping carts before?
Since you asked: if your needs are that limited, it does sound like a DIY situation to me. I don't see what's so fiddly about it; what complexity there is is all in the pricing formula, and you're planning to supply that either way. Add in Django's built-in session support and you're most of the way there.
There is an open source solution available: http://www.getlfs.com
I don't know if you could tweak it to suit you but it's based on the technologies you mention. The license is very liberal and it is heavily maintained.

Categories

Resources