0

I am currently working on a small data ‘reporting’ application. The idea behind it is to be able to import data from a specific location (be it a flat file or a remote database) and report on that data (e.g. Sales) following specific ‘dimensions’ (e.g. Sales by region, by product, by customer). At first when I built it, I created a ‘Sales’ model with these dimensions as FK’s to other models (a Region model, a Product model, a Customer model). The reporting aspect of the application is simply a bunch of requests on that table ending up in charts---this works fine.

Now let’s say I want to deploy/scale this application to multiple users; each user would have its own dataset, e.g. User A wants to report on Sales (by region, product and customer) while User B wants to report on Production volumes (by product, by plant and by month). What would be the best way to handle this? Is there a way to make the data model abstract from the underlying data sets?

I’ve had a quick look at various solutions such as:

  1. Django dynamic models

    This could be an interesting approach however looking at the code it seems like it's only possible to add/remove fields dynamically---what I would need is to add/remove models dynamically.

  2. NoSQL or any unstructured database backend

    This could be an option from what I have seen but I have no experience with those so it's difficult to assume.

  3. Any EAV type of data model

    Same as for (1) I am under the impression that this could work for fields, but rather not for entire tables.

  4. Serialization using JSONField to store data

I’m struggling to see how I could take this forward using Django (at some point I feel like I’m (wrongly) trying to build a DBMS all over again).

Any help is appreciated !

Cheers, J–

jlibioul
  • 83
  • 3
  • 10
  • Can you not put all potential reporting criteria in your model (region, product, customer, product, plant, month) then have different views to generate different reports? – Dan Russell Apr 21 '15 at 19:42
  • This could be a solution -- but how do I manage the fact that some users will look at Sales by region and product while others will look at Sales by product and customer? This in my opinion would be two different models, with different `models.ForeignKey()` fields, wouldn't it? – jlibioul Apr 21 '15 at 20:42
  • For example, you could have a view `sales_by_region` and another view `sales_by_product`. Then add a user profile (http://stackoverflow.com/a/965883/1623026) with a field like `preferred_sales_view`. Then you could have a button the user clicks like "View Sales" and set the target dynamically based on the value of `preferred_sales_view`. Either it directs to `sales_by_region` or to `sales_by_product`. – Dan Russell Apr 22 '15 at 16:04
  • Thanks -- maybe it's me but I still don't see it. Sales by region and Sales by product would be represented by two distinct Django models/Python classes since the data will not be the same. So how can I foresee in advance these models without knowing what the actual data will be? – jlibioul Apr 23 '15 at 07:57
  • Why will "the data not be the same"? Can't a single sale have both a region and a product? It sounds like you just want different ways to view the data stored in your `Sales` model, which should happen at the view level, not the model level. – Dan Russell Apr 23 '15 at 16:31

1 Answers1

0

For example, something like:

models.py:

class Sale(models.Model):
    seller = models.ForeignKey(Vendor)
    buyer = models.ForeignKey(Customer)
    product = models.ForeignKey(Product)
    region = models.ForeignKey(Region)

and views.py:

def sales_by_product(request, product_id):
    product_sales = Sale.objects.filter(product=product_id)
    return render_to_response('sales_report.html', {'sales':product_sales,}, context_instance=RequestContext(request)))

def sales_by_region(request, region_id):
    regional_sales = Sale.objects.filter(region=region_id)
    return render_to_response('sales_report.html', {'sales':regional_sales,}, context_instance=RequestContext(request)))

def all_sales(request):
    return render_to_response('sales_report.html', {'sales':Sale.objects.all(),}, context_instance=RequestContext(request)))

And if you want, in models.py, something like:

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    preferred_report = models.CharField(max_length=1, choices=(('P','Product'),('R','Region'),))
    region = models.ForeignKey(Region)
    favorite_product = models.ForeignKey(Product)

Then in views.py:

def user_sales_report(request):
    profile = request.user.get_profile()
    if profile.preferred_report == "P":
        HttpResponseRedirct('/sales/product/%i/' % profile.favorite_product_id)
    elif profile.preferred_report == "R":
        HttpResponseRedirct('/sales/region/%i/' % profile.region_id)
    else:
        HttpResponseRedirect('/sales/all/')

The above forces the user to view either a region's sales or a product's sales depending on the value of preferred_report. If it were me, however, and there were no reason not to, I'd just allow the user to select the criteria for how to view sales. Like use django-filter to allow him/her to pick as many criteria from your Sale model as they'd like to view the data for.

Dan Russell
  • 960
  • 8
  • 22
  • Hi Danos, thanks for this. This is exactly where I was at, but I can't find an answer to my question there: how can I make this abstract from the underlying data? In fact, you hardcode "Sales" whereas I don't know upfront what the underlying data (nor dimensions) will be. I'm rather looking for something like `class Cube(models.Model): dimensions = ListField()`. See what I mean? – jlibioul Apr 25 '15 at 21:38