Let say I have one model for cars. Each car has attributes: color, size, weight, etc... I want users to allow the creation of new attributes for each car objects. However I want to share "attributes" so that the attribute "size" only exists once in the db but values exist for each object where users have added them.
My old approach were two models: Car, KeyValue(key: String, value:String) and Car had a 1:m relationship to KeyValue.
Now, to ensure my above constraint I thought of the following:
Three objects: Car, Key, Value
Value(Key: Key)
Car (1:m relation to Value)
However, this reverse approach works very well but does not look "clean" to me. Therefore, I'd like to ask whether a cleaner approach is possbile.
i read this
http://www.craigkerstiens.com/2012/06/11/schemaless-django/
i haven't used this but i think it's ok.
a less complex approach is
django-picklefield
http://pypi.python.org/pypi/django-picklefield/
i hope this can help you
If your "choices" are malleable, i.e. they can be added to, edited, or deleted from, then the choice should be it's own model. For example:
class Color(models.Model):
name = models.CharField(max_length=50)
class Car(models.Model):
color = models.ForeignKey(Color, related_name='cars')
You should have Cars and CarModels
A CarModel has two list of properties. One that has the "PerModel" attributes for all cars of that models (That means all the cars of that model have the same value), and another one (just the names) of the properties that each car can have a different value "PerCar".
CarModel
{
KeyValue(key: String, value:String) propertyValuesPerModel;
List(String) propertyNamesPerCar;
}
Car
{
CarModel model;
KeyValue(key: String, value:String) propertiesPerCar; //Keys can only be those that appear on model.propertyNamesPerCar
}
Related
I have a below use case:
I have a method that accepts a list of strings. For each of the strings, I need to create a property under an existing google data store entity A
Example: I have an existing entity Person with properties fname and lname.
If the input list has strings - address, city, I need to update the entity Person to include these new properties address and city.
I'm coding this use case in Python. Any suggestions on how I can achieve this?
So the best way to do this is to let your class inherit ndb.Expando. The difference between Expando and Model is that you can always add attributes to an Expando entity and be able to store it in the Datastore.
Knowing this, there are several ways to proceed, but I am guessing you’re also going to need to use Python’s setattr(object, name, value) method to pass the attribute name from a string.
Take a look at the Expando model class: https://cloud.google.com/appengine/docs/standard/python/ndb/creating-entity-models#creating_an_expando_model_class
class Person(ndb.Expando):
pass
person = Person(fname='some', lname='body')
person_key = person.put()
...
person = person_key.get()
person.city = 'San Francisco'
person.address = '1234 Main St.'
person.put()
I have a scenario where a user need to enter a type of contribution. It can be cash or material. Based on his contribution type, I need to store the cash in IntegerField or material in CharField. How can I do it without making two fields in the model and leaving one always as empty field.
class Contribution(models.Model):
CONTRIBUTION_TYPE_CASH = "cash"
CONTRIBUTION_TYPE_MATERIAL = "material"
CONTRIBUTION_TYPE_CHOICES = [
(CONTRIBUTION_TYPE_CASH, _("cash")),
(CONTRIBUTION_TYPE_MATERIAL, _("material"))
]
contributor = models.ForeignKey(Contributor, related_name="donor", verbose_name=_("contributor"))
type = models.CharField(max_length=20, choices=CONTRIBUTION_TYPE_CHOICES, verbose_name=_("contribution type"))
First variant, keep a single CharField and make sure you properly validate input depending on type. You will have to deal with strings all the time, even if the actual value is a number.
Second variant, use model inheritance and define two different models, one for material contributions and another for cash contributions. You can use an abstract parent in which case you'd have to manually merge the two querysets for getting a global contribution list. Or you could use a concrete parent and use a third party package such as django_polymorphic to seamlessly deal with inherited instances. Either way you'd have to create the apropriate model instance in your backend, even if you use the same dynamic form in your frontend.
I have a group of related companies that share items they own with one-another. Each item has a company that owns it and a company that has possession of it. Obviously, the company that owns the item can also have possession of it. Also, companies sometimes permanently transfer ownership of items instead of just lending it, so I have to allow for that as well.
I'm trying to decide how to model ownership and possession of the items. I have a Company table and an Item table.
Here are the options as I see them:
Inventory table with entries for each Item - Company relationship. Has a company field pointing to a Company and has Boolean fields is_owner and has_possession.
Inventory table with entries for each Item. Has an owner_company field and a possessing_company field that each point to a Company.
Two separate tables: ItemOwner and ItemHolder**.
So far I'm leaning towards option three, but the tables are so similar it feels like duplication. Option two would have only one row per item (cleaner than option one in this regard), but having two fields on one table that both reference the Company table doesn't smell right (and it's messy to draw in an ER diagram!).
Database design is not my specialty (I've mostly used non-relational databases), so I don't know what the best practice would be in this situation. Additionally, I'm brand new to Python and Django, so there might be an obvious idiom or pattern I'm missing out on.
What is the best way to model this without Company and Item being polluted by knowledge of ownership and possession? Or am I missing the point by wanting to keep my models so segregated? What is the Pythonic way?
Update
I've realized I'm focusing too much on database design. Would it be wise to just write good OO code and let Django's ORM do it's thing?
Is there a reason why you don't want your item to contain the relationship information? It feels like the owner and possessor are attributes of the item.
class Company(models.Model):
pass
class Item(models.Model):
...
owner = models.ForeignKey(Company, related_name='owned_items')
holder = models.ForeignKey(Company, related_name='held_items')
Some examples:
company_a = Company.objects.get(pk=1)
company_a.owned_items.all()
company_a.held_items.all()
items_owned_and_held_by_a=Items.objects.filter(owner=company_a, holder=company_a)
items_on_loan_by_a=Items.objects.filter(owner=company_a).exclude(holder=company_a)
#or
items_on_loan_by_a=company_a.owned_items.exclude(holder=company_a)
items_a_is_borrowing=Items.objects.exclude(owner=company_a).filter(holder=company_a)
#or
items_a_is_borrowing=company_a.held_items.exclude(owner=company_a)
company_b = Company.objects.get(pk=2)
items_owned_by_a_held_by_b=Items.objects.filter(owner=company_a, holder=company_b)
#or
items_owned_by_a_held_by_b=company_a.owned_items.filter(holder=company_b)
#or
items_owned_by_a_held_by_b=company_b.held_items.filter(owner=company_a)
I think if your items are only owned by a single company and held by a single company, a separate table shouldn't be needed. If the items can have multiple ownership or multiple holders, a m2m table through an inventory table would make more sense.
class Inventory(models.Model):
REL = (('O','Owns'),('P','Possesses'))
item = models.ForeignKey(Item)
company = models.ForeignKey(Company)
relation = models.CharField(max_length=1,choices=REL)
Could be one implementation, instead of using booleans. So I'd go for the first. This could even serve as an intermediate table if you ever decide to use a 'through' to relate items to company like this:
Company:
items = models.ManyToManyField(Item, through=Inventory)
Option #1 is probably the cleanest choice. An Item has only one owner company and is possessed by only one possessing company.
Put two FK to Company in Item, and remember to explicitly define the related_name of the two inverses to be different each other.
As you want to avoid touching the Item model, either add the FKs from outside, like in field.contribute_to_class(), or put a new model with a one-to-one rel to Item, plus the foreign keys.
The second method is easier to implement but the first will be more natural to use once implemented.
For a little free fruit site, I have the following model relationship:
3 classes - Apples, Strawberries, and Locations
Apples and Strawberries list all "properties" of the fruits:
class Apple(models.Model):
treeSize = ...
age = ...
class Strawberry(models.Model):
fieldArea = ...
Now I want to record all locations with the fruits. So far I have a class with locations and attributes for Apples and Strawberries, which keeps the ForeignKeys to the kind of fruits. But that can't be it. It looks very inefficient, esp. if I add multiple other fruit types. Also, I would need to check that each location has at least one of the fruit keys.
class Location(models.Model):
lat = ...
lng = ...
appleType = models.ForeignKey(Apple, null = True)
strawberryType = models.ForeignKey(Strawberry, null = True)
Is there a better way to design the relationships or the model structure?
What would be the best practice for this problem?
Thank you for your advice!
This is a perfect case where you need to use the Generic Relations.
Instead of storing the Foreign Key to each one of those, you store the content type id (that recognizes Strawberries from Apples) and the object ids. You can of-course, develop this with your own conventions using the relevant strings within the Location model, but all that hard work is done for you in the django's built in Content Type Framework.
The description below is heavily simplified - it's only one part of a bigger problem that we are tackling but the innards can be safely left out for this question.
Suppose we have the following models: -
class Item(models.Model):
name = models.CharField(max_length=150)
value = models.DecimalField(max_digits=12,decimal_places=2)
class Person(models.Model):
name = models.CharField(max_length=150)
items = models.ManyToManyField(Item, through='AssignedItem')
class AssignedItem(models.Model):
person = models.ForeignKey(Person)
item = models.ForeignKey(Item)
value = models.DecimalField(max_digits=12,decimal_places=2)
So basically a person may be assigned zero, one, or more items and each assigned item's value may be overridden for a particular person by specifying the new value in the through model.
What we are aiming to achieve is an html table which has all the Item.name as its header row, with one extra column in that header row for Person.name.
Each Person may have a different set of Person.items assigned to them so it is expected that if a Person has not been assigned an Item, the corresponding cell for that Person will be blank (please see attached image).
The question is how to place the correct AssignedItem value in the corresponding column. We have a Queryset of Items that we are looping over in the template to create the header row, and then we have a list of lists containing each person's items. But how do we ensure that the correct AssignedItem is displayed under the corresponding Item header?
You mentioned you are constructing the list in the view,
We have a Queryset of Items that we
are looping over in the template to
create the header row, and then we
have a list of lists containing each
person's items.
When constructing this list, make the list an ordered list, where if a particular value exists, assign it and if it doesnt, then insert None.
ie, the list for Jake should look like [78, 45, None, 94, 72]
Edit:
Since reordering is an issue, use a dictionary with the item as index
ie, the values for Jake should look like {'Item1':78, 'Item2':45, 'Item4':94, 'Item5':72}
Well, the main issue was to ensure that the correct AssignedItem is displayed under the corresponding Item header.
I tried a lot of things in the template, but it did not offer too much room to maneuver. I ultimately created the "table" in the view then passed the string to the template for rendering.