Database and class design Django - python

I am building a website for selling bikes in django. I have a class Bike that will contain the bikes; it looks like this :
class Bike(models.Model):
brand = models.CharField(max_length=100)
model = models.CharField(max_length=100)
Now I would like to add a field wheels describing the wheels of the bike, and I would like this field to contain possibly several fields like the brand, size of the wheel. I would like these details on wheels implementation to be separated from the bike's class specification; however, I expect each wheel to be associated to exactly one bike.
An idea I had was to do the following :
class Wheels(models.Model):
description = models.CharField(max_length=100)
size = models.DecimalField(max_digits=5,decimal_places=2)
and then to include a new field in my bike :
class Bike(models.Model):
# previous fields
wheels = models.ForeignKey(Wheels)
I have however some doubts about it :
1) is it the correct design ? If I do that I will end up with a wheels' database which I don't think I actually need. I just want to have flexible fields in my bike database.
Basically I expect that I will have a one to one relationship between bikes and wheels.
2) If this is the correct design, then what I would like is to be able to add wheels on the fly while adding bike (never have to add wheels separately). What is the best way to do that ?
Thanks a lot for any hint / reference. I am a beginner with django...

I doubt that (in real life) you really will have a one-to-one relationship between bike and wheels - more than one bike model will surely use the same wheels.
Similar real life relationships exist between bike brands/models and components such as derailleurs, brakes, cranks, pedals etc.
By the way, you would not have separate databases for each component, each component would be modelled as a table within the same database.
So my advice is to go with the multiple table approach because you will eventually have the same components used on different bikes, and possibly vice versa for cases where there are optional components within the same basic bike model, e.g. same bike but different wheel sizes.

That design looks good to me - it's a good idea to keep individual objects in separate tables (in this case the components that make up the bike - particularly since they can be sold separately, and bikes can be customised with different parts)
I think a simple preset class inherited from the Bicycle class should do the trick:
class BicycleFrame(models.Model):
brand = models.ForeignKey(Brand)
model = models.CharField(max_length=100)
# class BicycleWheels, BicyclePedals etc..
class Bicycle(models.Model):
frame = models.ForeignKey(BicycleFrame)
wheels = models.ForeignKey(BicycleWheels)
pedals = models.ForeignKey(BicyclePedals)
# etc ...
class PresetBicycle(Bicycle):
pass
class PurchaseableMixin(models.Model):
user_id = models.ForeignKey(Customer)
def purchase(self):
# ... call this in the form handler to save this
# instance of a bike in the database and maybe
# email the customer to inform them of their purchase etc..
class Meta:
abstract = True
class PurchasedBicycle(Bicycle, PurchaseableMixin):
pass
.. then you can create a PresetBicycle in your admin area then in the view that you show to customers you could display the PresetBicycle by default and also provide a form to purchase it that is auto filled with the details for the PresetBicycle and that creates an instance of a PurchasedBicycle on submission (a JS framework like ReactJS and Backbone, or Angular might be best for the customer view).
Hope this helps!
P.S. Note that I haven't tested this approach myself - I'd suggest creating a few new branches in your Version Control (eg git) and setting up separate settings files for each one (import from a base settings file and use a separate database for each one to save having to mess around with too many migrations and obsolete tables) to test several approaches before making your final decision - it's good to figure this stuff out early on so that you don't end up making big structural changes later on.
P.P.S Also not that I've changed the brand field to be a ForeignKey, since you may later wish to filter on the brand..

Related

Correct way for nested python classes (or django foreign keys.) *Conceptual/engineering question*

This is more of a conceptual/engineering question than an actual programming question, but I keep going back and forth between what is the "right" thing to do here. For quick background, I am still a bit of a noob at python/django and don't have a ton of experience working with classes.
The program I'm trying to develop is an inventory management app.
There are multiple products but lets simplify and say one is shoes and one is clothing. Both products share some attributes (UPC, size, color, etc), but also have some unique attributes (shoe_width, clothing_type) as well.
Additionally, it seems like I should have a separate Product class (unique product attributes UPC, size shoe_width, clothing_type) and InventoryItem class (attributes unique to each piece of inventory such as price paid or condition) that inherits its corresponding Product class attributes.
EDIT2: clothing_type is unique to clothing, but shoe_width should be unique to the actual shoe InventoryItem and not the shoe Product. This sort of complicates the question, as now I'm thinking I'll need not only seperate Clothing and Shoe classes, but also ClothingInventoryItem & ShoeInventoryItem classes to deal with unique fields down at the inventory level.
Conceptually, I am trying to build this multi-purpose. Users should be able to view product information (not inventory related) and add products and inventory items via django admin or via spreeadsheet upload (spreadsheet hooks already built.)
So to the actual question, what is the correct way to implement the individual classes and what are some of the problems I may run into or drawbacks to doing so? I'm having a problem visualizing how this would work.
Should I:
A)
Have a ProductType field (make two initial entries of "Shoe" &
"Clothing")
Have separate "Shoe" and "Clothing" classes which inherit ProductType
via models.ForeignKey(ProductType). They would then have their own
unique fields regardless if they share some fields.
Have an InventoryItem class that then inherits Shoe or Clothing via ForeignKey.
The only limitation I can see is that the admin users would not be able to add new ProductType without me having to write a new class for that new ProductType (which is totally fine.)
Thanks in advance.
Edit: When I was initially typing this, the alternative scenario would be to do these relationships correctly via python nested classes and then feed the info into the django model classes...but this seems redundant and unnecessary.

How to share and specialize base models in different Django applications?

We are developing a collection management project using Django, usable for different types of collections.
This problem quite naturally divides itself in two:
The common part, that will be shared by all collections.
The specializations, different for each collection type.
Example
To illustrate this a bit further, let's take a simplified example in pseudocode.
Common part
class ItemBase: # ideally abstract
name = CharField()
class Rental
item = ForeignKey("Item")
rented_to_person = CharField()
Specialization for a collection of cars
class ItemSpecialization
horse_power = Int()
 The problem
The question is how we could organize the code in order to allow reuse of the common part without duplicating its content ?
We would imagine it would be best to have the common part as a non-installed application, and have each specialized configuration as a separate installed application. But this would cause a problem with the Rental concrete class, because it resides in the common-part application.
Any advices on how we could proceed ?
It really depends on what you want, you may use an abstract model class for common stuff, and inherit from that in specialized model classes.
Otherwise, if you really want one table for all common data, typically to be able to relate to it, then you'll need your specialized model to have a relation to the common model. It can be a foreign key, or you can use model inheritance, in which case the foreign key in question will be managed for you by django, but it'll be harder to use.
It sounds like you're looking for a OneToOneField field relationship. Based on your example:
class ItemBase:
name = models.CharField(max_length=50)
class Rental:
item = models.OneToOneField(ItemBase)
rented_to_person = models.CharField(max_length=50)
class ItemSpecialization
item = models.OneToOneField(ItemBase)
horse_power = models.IntegerField()
With this model hierarchy, you could fetch Rental or ItemSpecialzation objects and also gain access to ItemBase fields. It's basically OO inheritance for Django models. More details in the docs: https://docs.djangoproject.com/en/1.9/topics/db/examples/one_to_one/

When to use one-to-one relationships in Django models

I've read a few places (see the second answer) that one-to-one relationships in Django models should almost always only be used for inheritance, or to access an otherwise inaccessible model (like the Django user model).
However, it seems like there are cases where you have an object that will always have exactly one instance of another object where you would logically want to separate those two objects. Say, for example, your app was storing information about cars. Each car has exactly one driver and each driver only drives one car. Does it not make sense to separate car and driver into two separate models?
Imagine you have a company and make intranet tool listing all employees, their positions, offices, departments, salaries, etc. You would make in Django models.py a class Employee, maybe something like this:
class Employee(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
position = models.CharField(max_length=255)
office = models.CharField(max_length=20)
salary = models.IntegerField()
department = models.ForeignKey(Department, related_name='employees')
But for some reasons you don't want the salary to be accessible to all employees, maybe there are many people with redactor status in the admin area, and decide to outsource it to its own model and change the model Employee:
class Employee(models.Model):
# above attributes
salary = models.OneToOneField(Salary)
There are certainly other ways to hide this information, but one possibility is to divide the information in two tables even though it is just plain 1:1 relation.
Your company is a software company and you introduce pair programming. Every employee has a pair programming partner. It can be just one programming partner. So you adapt your model again:
class Employee(models.Model):
# above attributes
pair_programmer = models.OneToOneField('self')
This would be a recursive one-to-one relation.
One-to-one relations are not very common and hard to find in beginners' tutorials, but if there are some specific requirements, you find yourself creating 1:1 relation for solving the problem.
Here is a real life example from my work. I'm bioinformatician and make software for microorganisms. They are classed in genera and species. Every genus may contain one or more species, but a species can belong to only one genus. That is a clear 1:n relation. But now, a genus has a type species, only one and just one. And the type species can belong to one genus. Here I put models.OneToOneField, besides the models.ForeignKey.
Don't worry a lot about 1:1 relations in advance. When you come to some specific problem, then you'll figure out if you need 1:1 relation.
The django documentation gives a great answer:
For example, if you were building a database of “places”, you would
build pretty standard stuff such as address, phone number, etc. in the
database. Then, if you wanted to build a database of restaurants on
top of the places, instead of repeating yourself and replicating those
fields in the Restaurant model, you could make Restaurant have a
OneToOneField to Place (because a restaurant “is a” place; in fact, to
handle this you’d typically use inherit Each car has exactly one driver and each driver only drives one car. Does it not make sense to separate car anance, which involves an
implicit one-to-one relation).
Django uses OneToOne to model inheritance (and might use it internally, I haven't checked out the source though). I feel like if there is a tool django is providing and you can use that tool in a way that you can defend, why not use it? It seems like it makes sense, that if a car only has one driver, then enforce that in the db using the tools (OneToOneField) that django provides

Django ModelField for an object that is the target of ForgeinKeys on other objects

I have some Django objects like this:
class Award(Model):
name = CharField(...)
date = DateTimeField(...)
class Book(Model):
name = CharField(...)
award = ForgeinKey(Award, blank=True)
(i.e. each Book may or may not have one award)
I want to make a form for adding/editing Awards. Assume lots of Books have already been created. Initially I created a ModelForm like this:
class AwardForm(ModelForm):
class Meta:
model = Award
which created a correct form with all the data, however there was no way to add books to the award (or mark this award as applicable to the books that were selected).
I was going to manually add a ModelMultipleChoiceField to the AwardForm (with a queryset for the Books), then add logic to is_valid that would check the Books that were selected, and add something to save to go through the selected Books and set the forgein key on that object to this object.
However, Is there a good 'django' way to do this automatically? i.e. just add a certain field to the Form which will do that all itself? If I were to change the Book.award to be a Award.books manytomany key it would probably do all this automatically, but I like the internal logic of having that as a forgeinkey on the Book.
I was just going to suggest using Inline's but upon re-reading your question the hard part is selecting objects that already exist and linking them to the Award that you are editing.
The way that you have suggested is the first way that I would do it, and the only other way I can think of would involve hacking away at some of the methods on your AwardAdmin to add in the functionality that you desire.
Using the ModelMultipleChoiceField though seems like quite a clean way of doing it to be honest, especially since you shouldn't really need much/any editing of the save method as the field should handle that itself?

Structuring Django-App to Attach Custom Business Rules to Object Instances

I'm torn how to structure my code to accommodate business rules specific to instances of a particular model.
For example. Lets say I have a Contact model with a type field and choices=(('I','Individual'),('C','Company)). Based on the type of model that I have, I might want to have custom methods.
So thinking out loud, something like this would be nice:
class IndividualContact(Contact):
""" A custom class used for Contact instances with type='I' """
criteria = Q(type='I')
# The goal here is that Contact is now aware of IndividualContact and constructs
# objects accordingly.
Contact.register(IndividualContact)
Or even:
class SpecialContact(Contact):
""" A custom class used for the contact with pk=1 """
criteria = Q(pk=1)
At which point I have a nice home for my special instance specific code.
One of the alternatives I explored is using model inheritance and avoiding things like type fields that impart new behaviors. That way, new classes plug into the existing framework elegantly and you're nicely set up to add custom fields to your different types in case you need them.
In my case I have a resource crediting system on the site that allows me to say things like "You may only have 2 Listings and 20 Photos". Individual resource types are rationed, but there is a generic credit table that gives you credits for various content types. The logic that goes into counting up your Listings and Photos varies based on the type of object you're working with.
I.E.:
listing_credit = Credit.objects.create(content_type=ContentType.objects.get_for_model(Listing), user=user, credit_amt=2)
# Should subtract **active** listings from current sum total of Listing credits.
listing_credit.credits_remaining()
photo_credit = Credit.objects.create(content_type=ContentType.objects.get_for_model(Photo), user=user, credit_amt=5)
# Photos have no concept of an active status, so we just subtract all photos from the current sum total of Listing credits.
# Also, the Photo might be associated to it's user through a 'created_by' field whereas
# Listing has a user field.
photo_credit.credits_remaining()
My current approach is separate classes but I'd like to reduce that boilerplate and he necessity of creating N separate tables with only a credit_ptr_id.
Take a look at django proxy models. They allow you to do exactly what you want.
http://docs.djangoproject.com/en/dev/topics/db/models/#proxy-models
But since in you case the behavior is dependent on the field value, then you should add custom managers to the proxy models that retrieve items only of only that type on queries.

Categories