How would I represent and model this relation? - django

So I have the following logic. A user creates a trade, this trade contains items a user wants and items a user has. These has and wants are represented as two separate many to many relationships.
However, here is where I am getting a little confused. These items can come from different models. For example I have a model set up for particular items, say business items which have unique characteristics and a second model for engineer items. Now these items can both be traded within the same trade.
Furthermore if I were to add more models representing other unique trade items how would I be able to add this to the many to many relationship without overhaul of the structure or data.
For illustration:
class ItemTrade(models.Model):
id = models.CharField(max_length=10, primary_key=True)
user = models.ForeignKey(get_user_model())
have_items = models.ManyToManyField()
want_items = models.ManyToManyField()
num_watch = models.IntegerField(max_length=10)
num_views = models.IntegerField(max_length=20)
class Model1(models.Model):
index = models.IntegerField(max_length=20, primary_key=True)
name = models.CharField(max_length=100)
type = models.ForeignKey('DotaItemType',null=True,blank=True)
class Model2(models.Model):
index= models.IntegerField(max_length=20, primary_key=True)
name = models.CharField(max_length=100)
type = models.ForeignKey('DotaItemType',null=True,blank=True)
desc = models.CharField(max_length=20)
The indexes will overlap for each item which means that I would also need to have secondary field to identify which model the item belongs to. What is the best possible method to represent this relation?
The only way I can think of is to have a unique many to many field for each model relation within the trade but I am not sure if this is the simplest and most effective way of accomplishing this.

Related

Django model organization: food item locations in different grocery stores

I'm working on a cookbook app and I want to sort the ingredients of a recipe by their aisle in the grocery store. Since different grocery stores have different configurations, I want users to be able to sort the lists of ingredients by a selected store. I'm new to Django and am stuck on figuring out the models that I'll need for this. I think I want to have a many to many relationship between my Food model and a Store model. I think I want to use the through argument and have another intermediary Location model that connects the 'Food' and 'Store' and also contains which the aisle.
If possible, I'd like to have the choices for aisle have a certain description that depends on the selection of the Store object
class Food(models.Model):
name = models.CharField(max_length=100)
grocery_aisle = models.ManytoManyField(Store, through='Location')
class Store(models.Model):
name = models.CharField(max_length=100)
aisles = { # Not really sure how to store this kind of information which would be different for each Store object.
0: 'Produce Section',
1: 'Aisle 1: bread and peanutbutter',
2: 'Frozen Desserts',
3: 'Pharmacy'
}
class Location(models.Model):
food = models.ForeignKey(Food, on_delete=models.CASCADE)
store = models.ForeignKey(Store, on_delete=models.CASCADE)
aisle = models.SmallIntegerField(choices=MEASUREMENT_CHOICES) # option descriptions depend on selected store object
Any ideas would be greatly appreciated. I like Django a lot so far, but this is my first time using it, so I'm fumbling a bit.
Try this. It'll allow you to store multiple Aisles within a Store, then assign every Food to multiple Aisles using a many-to-many relationship.
class Store(models.Model):
name = models.CharField(max_length=100)
class Aisle(models.Model):
name = models.CharField(max_length=100)
store = models.ForeignKey(Store)
class Food(models.Model):
name = models.CharField(max_length=100)
aisle = models.ManytoManyField(Aisle)
class Recipe(models.Model):
name = models.CharField()
food = models.ManyToManyField(Food)
def find_in_store(self, store):
"""
Write a method here that finds a given recipe in a store, and call it with recipe.find_in_store(store). This will be a bit of a complex function, but a naive implementation (if you are running a small-scale project) would be to loop through all Aisle objects in the given store and determine whether any Food objects needed for the Recipe can be found in the given Aisle.
"""

How to retrieve a set of objects, filtered and ordered by fields of other objects, for which the desired object is a foreign key?

To rephrase the title to the context of my problem: How to retrieve a set of foods, filtered and ordered by fields of other objects, for which the food object is a foreign key?
I have the following models:
class Food(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=200)
description = models.CharField(max_length=200, blank=True)
class DayOfFood(models.Model):
user = models.ForeignKey(User)
date = models.DateField()
unique_together = ("user", "date")
class FoodEaten(models.Model):
day = models.ForeignKey(DayOfFood, on_delete=models.CASCADE)
food = models.ForeignKey(Food, on_delete=models.CASCADE)
servings = models.FloatField(default=1)
I want to be able to retrieve the foods that a given user ate most recently. This collection of foods will be passed to a template so it must be a QuerySet to allow the template to loop over the food objects.
This is how far I got
days = DayOfFood.objects.filter(user=request.user)
foodeatens = FoodEaten.objects.filter(day__in=days)
foodeatens = foodeatens.order_by('day__date')
Now it feels like I am almost there, all the foods I want are contained in the FoodEaten objects in the resulting QuerySet. I do not know how to use "for ... in:" to get the food objects and still have them stored in a QuerySet. Is there a way to perform foreach or map to a QuerySet?
I do not want to rewrite the template to accept FoodEaten objects instead because the template is used by other views which do simply pass food objects to the template.
The solution
The answer from Shang Wang helped me write code that solves my problem:
days = DayOfFood.objects.filter(user=request.user)
foods = Food.objects.filter(
foodeaten__day__in=days,
foodeaten__day__user=request.user) \
.order_by('-foodeaten__day__date')
That could be done using chain of relations:
Food.objects.filter(foodeaten__day__in=days,
foodeaten__day__user=request.user) \
.order_by('foodeaten__day__date')
By the way, I'm not sure why do you have user on multiple models Food and DayOfFood. If you really need user relations on both of them, maybe make the field name more explicit with the user's role in each model, otherwise you will get confused very quickly.

Many foreign keys in one lookup table. Bad idea?

I am using Django, and my tables look like
class Product(models.Model):
category = models.CharField(max_length=50)
title = models.CharField(max_length=200)
class Value(models.Model):
name = models.CharField(max_length=200, unique=True)
class Attribute(models.Model):
name = models.CharField(max_length=200)
parent = models.ForeignKey('self', related_name='children')
values = models.ManyToManyField(Value, through='ProductAttributeRelationship', related_name='values')
class Meta:
unique_together = ('name', 'parent')
class ProductAttributeRelationship(models.Model):
product = models.ForeignKey(Product, related_name='products')
value = models.ForeignKey(Value, related_name='values')
attribute = models.ForeignKey(Attribute, related_name='attributes')
class Meta:
unique_together = ('product', 'value', 'attribute', 'price')
class Price(models.Model):
regular = models.IntegerField(blank=True, null=True)
sale = models.IntegerField(blank=True, null=True)
on_sale = models.NullBooleanField(blank=True)
created = models.DateTimeField(auto_now=True)
relation = models.ForeignKey(ProductAttributeRelationship)
class Meta:
unique_together = ('regular', 'sale', 'on_sale', 'sale_percentage')
Is it a bad idea to have the 3 ForeignKeys in ProductAttributeRelationship and the ForeignKey to that in Price since a ProductAttributeRelationship may have many prices? I don't have much knowledge in this area, and have been reading up about the 5 normalized forms, but am not sure where I should, or could, fit into the recommended 3rd form.
We declare a foreign key when a value for a subrow in one table has to appear as a value of a subrow in another table. That's what you have, so declare them.
Foreign keys have nothing to do with normalization per se. A normal form is something that a table is or isn't in. Normalization is about replacing a table by multiple tables that always join to it. A foreign key constraint holds when two tables have to agree per above. It can happen that new foreign keys holds between new tables from normalizing but if so you would just declare them. They don't affect what normal forms a table is in or normalization.
(Although ProductAttributeRelationship product, value, attribute and relationship are unique, presumably it is because product and price are unique, and product has just one price and an attribute has just one value. So you should say that product and price are unique; then all four have to be. Similarly, although Price regular, sale, on_sale and sale_percentage are unique, if regular, sale and on_sale are unique with sale_percentage a function of them then you should declare the three unique.)
(PS: 1. The main issue is integrity: If there is no constraint on the subset then invalid updates are allowed. 2. If the subset is unique then the superset is unique. So if the DBMS is enforcing subset uniqueness then it is enforcing superset uniqueness. 3. Moreover every superset of a CK is unique so there's nothing special about the particular extra columns you chose. 4. SQL DBMS UNIQUE/PK usually come with an index taking space and time to manage. For integrity and basic efficiency/optimization that's wasted on non-CK columns. But there can always be other special-case reasons for indexing. 5a. One reason to declare a non-CK superkey is that SQL forces you to do so to use it as a FK target. (You can either consider this redundancy as a helpful check or a tedious obtuseness.) 5b. Another reason is that sometimes this allows declarative (vs procedural/triggered) expression of integrity constraints via FK checking.)

Selecting distinct nested relation in Django

To describe the system quickly, I have a list of Orders. Each Order can have 1 to n Items associated with it. Each Item has a list of ItemSizes. Given the following models, which have been abbreviated in terms of fields for this question, my goal is to get a distinct list of ItemSize objects for a given Order object.
class ItemSize(models.Model):
name = models.CharField(max_length=10, choices=SIZE_CHOICES)
class Item(models.Model):
name = models.CharField(max_length=100)
sizes = models.ManyToManyField(ItemSize)
class OrderItem(models.Model):
order = models.ForeignKey(Order)
item = models.ForeignKey(Item)
class Order(models.Model):
some_field = models.CharField(max_length=100, unique=True)
So... if I have:
o = Order.objects.get(id=1)
#how do I use the ORM to do this complex query?
#i need o.orderitem_set.items.sizes (pseudo-code)
In your current set up, the answer by #radious is correct. However, OrderItems really shouldn't exist. Orders should have a direct M2M relationship with Items. An intermediary table will be created much like OrderItems to achieve the relationship, but with an M2M you get much simpler and more logical relations
class Order(models.Model):
some_field = models.CharField(max_length=100, unique=True)
items = models.ManyToManyField(Items, related_name='orders')
You can then do: Order.items.all() and Item.orders.all(). The query you need for this issue would be simplified to:
ItemSize.objects.filter(item__orders=some_order)
If you need additional data on the Order-Item relationship, you can keep OrderItem, but use it as a through table like:
class Order(models.Model):
some_field = models.CharField(max_length=100, unique=True)
items = models.ManyToManyField(Items, related_name='orders', through=OrderItem)
And you still get your simpler relationships.
ItemSize.objects.filter(items__orderitems__order=some_order)
Assuming you have reverse keys like:
ItemSize.items - reverse fk for all items with such size
Item.orderitems - reverse for all orderitems connected to item
Item.orders - you can guess ;)
(AFAIR that names would be choose by default, but I'm not sure, you have to test it)
More informations about reverse key queries are available in documentation.

Django: distinct QuerySet based on a related field

In my Django app I allow users to create collections of movies by category. This is represented using 3 models, Movie, Collection, and Addition (the Addition model stores movie, collection, and user instances). Simplified versions of all three models are below.
class Movie(models.Model):
name = models.CharField(max_length=64)
class Collection(models.Model):
name = models.CharField(max_length=64)
user = models.ForeignKey(User)
class Addition(models.Model):
user = models.ForeignKey(User)
movie = models.ForeignKey(Movie)
collection = models.ForeignKey(Collection)
So for example a user could create a collection called "80's movies", and add the movie "Indiana Jones" to their collection.
My question is: how do I display a distinct list of movies based on a set of query filters? Right now I am getting a bunch of duplicates for those movies that have been added to more than one collection. I would normally use distinct() to get distinct objects, but in this case I need distinct movies rather than distinct additions, but I need to query the Addition model because I want to allow the user to view movies added by their friends.
Am I setting up my models in an optimal way? Any advice/help would be much appreciated.
Thanks!
First. I don't think you need Addition model here. You try to create many-to-many relation, but there's documented way of doing this:
class Movie(models.Model):
name = models.CharField(max_length=64)
class Collection(models.Model):
name = models.CharField(max_length=64)
user = models.ForeignKey(User)
movies = models.ManyToManyField('Movie', blank=True, null=True)
Second. The documentation says: "To refer to a "reverse" relationship, just use the lowercase name of the model".
So the answer is (for the setup above):
Movie.objects.filter(collection__user=user).distinct()