views:

63

answers:

3

Here's what I'm thinking (excuse the Django format):

class VehicleMake(Model):
    name = CharField(max_length=50)

class VehicleModel(Model):
    make = ForeignKey(VehicleMake)
    name = CharField(max_length=50)

class VehicleYear(Model):
    model = ForeignKey(VehicleModel) # or ManyToManyField
    year = PositiveIntegerField()

This is going to be used in those contingent drop-down select boxes, which would visually be laid out like [- Year -][- Make -][- Model -]. So, to query the data I need I would first have to select all distinct years from the years table, sorted descending. Then I'd find all the vehicle makes that have produced a model in that year. And then all the models by that make in that year. Is this a good way to do it, or should I re-arrange the foreign keys somehow? Or use a many-to-many table for the years/models so that no year is repeated?

+1  A: 

I'm by no means an expert but I think it would go something like this?

class VehicleModel( Model ):
    name = CharField( max_length=50 )
    year = PositiveIntegerField()
    manufacturer = ForeignKey( VehicleManufacturer )

class VehicleManufacturer( Model ):
    name = CharField(max_length=50)

There doesn't need to be a separate class/table for year, just insert them directly. Though I have not thought of all the possibilities, can you tell me if this would fit?

meder
+1 I was typing out almost exactly this when I got the new answer posted popup :)
Nicholas Knight
Huh? I think you're thinking that I want "Vehicle" to refer to a specific instance of a vehicle, but I'm trying to store some data so that he can *choose* vehicles. With what you have there, ... `Vehicle.name` would refer to the manufacturer? This string would be repeated for every row? Year would be what? Year is supposed to indicate the years (plural) that a car manufacturer produced a particular model.
Mark
I see your revision now... still, I'd have to repeat model names for every year that it was released. Not sure how I feel about that.
Mark
+1  A: 

I am probably oversimplifying this, but what's wrong with having a simple table with make, model and year in it? Yes, the make string is going to be duplicated in every row, but realistically - how many rows you expect in that table?

class Vehicle( Model ):  
    name = CharField( max_length=50 )  
    year = PositiveIntegerField()  
    model = CharField( max_length=50 )  
Franci Penov
I was thinking about this too. This is a definite possibility... I haven't done the math yet, but I would expect a few thousand rows actually. There's what, like 300 car manufacturers out there? (http://en.wikipedia.org/wiki/List_of_car_manufacturers), and they each have on average say 5 different models, which they might produce for 10 years = 300 * 5 * 10 = 15000 rows; that's a fair bit.
Mark
@Mark Yes but unless you're storing additional information for either the make, model or year then each one of those is a primary key for their respective domains and Franci Penov's answer is correct. Splitting the domains into different tables is only advantageous in the sense that an integer column is smaller than a char(50) column.... but that's a premature optimization.
Rodrick Chapman
@noblethrasher: Prevents typos too when entering in all that data :p If the make/model differs by even a single letter then I will have duplicates when I run my `SELECT DISTINCT name FROM vehicle_makes` query. Also... I don't know how expensive "distinct" is.
Mark
@Mark That's a good point. In any case I would personally put them in three different tables (I'd even have a year table which I suspect a lot of people might consider wasteful) but my considerations are a bit different.
Rodrick Chapman
I am not really sure how having the make in a separate table would stop you from creating both Toyota and Toiota. The input validation is function of the user interface, not a function of the database; autocomplete helps quite a lot with preventing typos like that. Having a separate table - not so much by itself... :-)
Franci Penov
@Franci: Well... you'd only have to type Toyota once rather than 500 times. Less likely to make a mistake, and if you do, you only have to fix it in one place.
Mark
@noblethrasher: What *are* your considerations? You seem to be in agreement with me. Is it better to use an m2m table to avoid repeating years, or as I have it there?
Mark
@Mark - you are over-architecting this.
Franci Penov
@Mark, a full explanation is too long for a comment. Suffice it to say, some people think of a table as a set of relations and complain that SQL does not respect the relational model because it allows duplicates or requires/encourages primary keys. A table is more usefully thought of as a bound on a search space (an index is a contraction on that space). When you create one, you're telling the database where to start searching and how far away to search (which is why a table isn't just a true set; it must have an ordering). Everything in RDB design is centered on that concept. Feel free to PM.
Rodrick Chapman
+1  A: 

I would go for:

  class VehicleModel( Model ): 
    name = CharField( max_length=50 ) 
    first-year = PositiveIntegerField()
    last-year = PositiveIntegerField() 
    make = ForeignKey( make ) 

class Make( Model ): 
    name = CharField(max_length=50) 
    manufacturer = ForeignKey( VehicleManufacturer ) 

class VehicleManufacturer( Model ): 
    name = CharField(max_length=50) 

This should allow you to group up Buick, Chevrolet, Cadilac etc. under "General Moters"

Also I think your UI logic is slightly flawed, This shouds like a job for a "walk right" menu, ie, you need a pulldown of all your manufacturers, when a particular manufacturer is selected you can present a sub-menu of models, when a model is selected you can then preset a sub menu of years.

Alternativly you should edit the contents of the "model" selection whenever a new manufacturer is selected, then whenever a model is selected the year selection should be updated.

As described your UI would allow me to enter a "Studebaker" "Model T" "2010"

James Anderson
Yes... that's exactly what I meant by "contingent drop-downs". Except I want them to select the year first, which filters the makes, which filters the models. I don't think your first/last year logic works because I'm pretty sure manufacturers like to skip years (BMW 5 series comes to mind).
Mark
On second thought... I think most models *do* start and stop at specific years. The odd-balls can be entered twice as separate entries. Cuts down on a table or two and saves me from killing myself entering all that data...
Mark