Django bulk update for many to many relationship - django

I have and Event and EventCategory model with a many-to-many relationship.
There are 2 event categories - past (ID of 2) and future (ID of 1).
I want to find all Events in the future via
models = Event.objects.filter(categories__slug='future')
And then update them so they are all in the past.
Should I create a list of the Event instances, then delete from the related table, and insert the instances with the new category ID - just wanted some guidance if possible, on the most efficient way to do this.
Many thanks

I am not sure if this is the most efficient solution for my needs but it works:
Find the new category I want to associate to the events (this is the "past" category)
cat = EventCategory.objects.get(pk=2)
Here are my existing relationships, where 1 is the ID of the future category
models = Event.objects.filter(categories__id=1)
for model in models:
model.categories.clear()
model.categories.add(cat)
Now all of the entires in the related table are in the past category.

Related

Symfony2 DQL Update query with Many to Many

I have three tables "category", "product" and "product_category".
First two tables are created from two entity Category and Product.
Third table "product_category" is auto generated by framework doctrine console command.
Now I can get (fetch) product relational data (based on category id) from below query, which is fine.
$this->createQueryBuilder('p')
->leftJoin('p.category', 'c')
->select('p')
->where('c.id = :category_id')
->setParameter('category_id', 2)
->getQuery()->getSQL();
But how can I use Many-to-Many relation to Update Data?
I had Tried with several queries but its not working!!!
( I want to update all product status to inactive (2), whose category status is (2 = Inactive).
When doing a query on a table that has children. You can also just fetch the parent item, and doctrine will automatically handle the child objects. If you have a getCategory within the Product entity, it will resolve the category automatically.
Probably what you are looking for is cascading of events. of which is explained within Doctrine 2 ManyToMany cascade

Django - joining multiple tables (models) and filtering out based on their attribute

I'm new to django and ORM in general, and so have trouble coming up with query which would join multiple tables.
I have 4 Models that need joining - Category, SubCategory, Product and Packaging, example values would be:
Category: 'male'
SubCategory: 'shoes'
Product: 'nikeXYZ'
Packaging: 'size_36: 1'
Each of the Model have FK to the model above (ie. SubCategory has field category etc).
My question is - how can I filter Product given a Category (e.g. male) and only show products which have Packaging attribute available set to True? Obviously I want to minimise the hits on my database (ideally do it with 1 SQL query).
I could do something along these lines:
available = Product.objects.filter(packaging__available=True)
subcategories = SubCategory.objects.filter(category_id=<id_of_male>)
products = available.filter(subcategory_id__in=subcategories)
but then that requires 2 hits on database at least (available, subcategories) I think. Is there a way to do it in one go?
try this:
lookup = {'packaging_available': True, 'subcategory__category_id__in': ['ids of males']}
product_objs = Product.objects.filter(**lookup)
Try to read:
this
You can query with _set, multi __ (to link models by FK) or create list ids
I think this should work but it's not tested:
Product.objects.filter(packaging__available=True,subcategori‌​es__category_id__in=‌​[id_of_male])
it isn't tested but I think that subcategories should be plural (related_name), if you didn't set related_name, then subcategory__set instead od subcategories should work.
Probably subcategori‌​es__category_id__in=‌​[id_of_male] can be switched to .._id=id_of_male.

Fetch objects with its relation source objects

The models:
class Offer(models.Model):
desc = models.TextField()
class Bid(models.Model):
offer = models.ForeignKey(Offer)
So there may be many bids for one offer.
Is there any way to fetch all offers, with its bids without performing query for each offer ?
There's a table with offer list, and I need to add a "B" flag in every row if there's at least one bid.
I tried with prefetch_related(). This worked fine. I got a "bids" attribute attached (as list) for every offer instance, but it resulted in num_offers queries.
offers = Offer.objects.prefetch_related(
models.Prefetch('bid_set', to_attr='bids', queryset=Bid.objects.select_related()))
Since you are querying from the Offer Model which is 1 to many, then the only available way is to actuallty perform 2 queries (1 for the Offer and 1 for all related bids)
offers = Offer.objects.prefetch_related('bid_set').annotate(number_of_bids=models.Count('bid_set')).all()
On the other hand, you can create a query from the other side, from the Bid towards the Offer, that would create a singe query with a JOIN:
bids = Bid.objects.select_related('offer').all()
offers = [o.offer for o in bids]
Which one you prefer depends on what you want and how your data is structured or how many entries your DB contains.
Annotate will produce a virtual number_of_bids field containing the number of bids for each offer.

How to join non-relational models in Django 1.3 on 2 fields

I've got 2 existing models that I need to join that are non-relational (no foreign keys). These were written by other developers are cannot be modified by me.
Here's a quick description of them:
Model Process
Field filename
Field path
Field somethingelse
Field bar
Model Service
Field filename
Field path
Field servicename
Field foo
I need to join all instances of these two models on the filename and path columns. I've got existing filters I have to apply to each of them before this join occurs.
Example:
A = Process.objects.filter(somethingelse=231)
B = Service.objects.filter(foo='abc')
result = A.filter(filename=B.filename,path=B.path)
This sucks, but your best bet is to iterate all models of one type, and issue queries to get your joined models for the other type.
The other alternative is to run a raw SQL query to perform these joins, and retrieve the IDs for each model object, and then retrieve each joined pair based on that. More efficient at run time, but it will need to be manually maintained if your schema evolves.

How to model lending items between a group of companies

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.