Filter based on number of manytomany - python

I have models defined as follow:
class Employee(models.Model):
...
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
class Project(models.Model):
...
employees = models.ManyToManyField(Employee, null=True, blank=True)
I'm trying to retrieve all the projects that have at least one employee assigned to them, but I don't know how. I tried the following things:
projects.filter(employees__gt=0)
where projects = Project.objects.all() but I don't think this is the right query, because if I do projects.filter(employees_lte=0) it returns nothing, even if I have projects with no employees assigned. How can I retrieve what I'm looking for? Could you point to a page where I can find all the lookups I can use?
Thanks!

You can try like this using isnull:
Project.objects.filter(employees__isnull=False)
Update
If you want to check specific number of employees, maybe try like this
from django.db.models import Count
Project.objects.annotate(employee_count=Count('employees')).filter(employee_count__gt=5)

Related

Django - Filter queryset by another queryset through related field

Suppose I have the two models below and I want to get a queryset of all developers that have games where the platform field matches a certain value. How would I go about that?
class Developer(models.Model):
name = models.CharField(max_length=100, default="Unknown")
class Game(models.Model):
name = models.CharField(max_length=300)
developer = models.ForeignKey(Developer, related_name="games", on_delete=models.CASCADE)
platform = models.CharField(max_length=40)
I tried a few approached but can't seem to figure anything out that works.
You can query this with:
Developer.objects.filter(games__platform='name-of-platform').distinct()
Without the .distinct() [Django-doc], the same developer will be returned multiple times, if they developed multiple Games for the same platform. If that is not a problem, you can of course omit the .distinct().

Django annotate on several fields related to same model

I have two models:
class Account(models.Model):
...
class Transaction(models.Model):
....
account = models.ForeignKey(Account)
source_account = models.ForeignKey(Account, null=True)
I need to display the number of transactions for each of a user's accounts. Django's annotate seemed like the proper tool for this task. I did:
queryset = models.Account.objects.filter(user=self.request.user)
queryset.annotate(transactions_count=Count('transaction'))
This gives the correct number for transactions with account field set to the predicate account but leaves out transactions where source_account is set to the predicate account.
Using the Django shell I am able to do something like:
accounts_count = user_transactions.filter(Q(account=account)|Q(source_account=account)).count()
This gives the correct answer. Is there something I am doing wrong? Can someone point me in the correct direction. Any assistance is highly appreciated.
I would set related_name to your ForeignKey fields. Then it's a bit easier to work with them. So for example in your models let's set:
class Transaction(models.Model):
...
account = models.ForeignKey(Account, related_name='transactions')
source_account = models.ForeignKey(Account, null=True, related_name='source_transactions')
then can do something like:
queryset = models.Account.objects.filter(user=self.request.user).annotate(transactions_count=(Count('transactions')+Count('source_transactions'))
it would work without the naming too, it's just more readable and easier. The main point is adding the two Count as one field in annotate.
The best approach for these types of problems is to imagine them in raw SQL and then try to mimic it in Django ORM.
(in raw sql you would also simply just add two columns like SELECT (a.col + a.col2) AS count
The problem is that your transaction has to ForgeinKeys to Account. I would suggest trying something like this
class Transaction(models.Model):
....
account = models.ForeignKey(Account, related_name="transaction_account")
source_account = models.ForeignKey(Account, null=True, related_name="transaction_source_account")
Then in your query:
queryset.annotate(transactions_count=((Count('transaction_account') + Count('transaction_source_account'))

Large ManyToMany relations on django admin form

So, I have the following models:
class Band(models.Model):
name = models.CharField(max_length=50)
class Contract(models.Model):
band = models.ForeignKey(Band)
when = models.DateTimeField(auto_now_add=True)
salary = models.IntegerField()
class Musician(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
bands = models.ManyToManyField(Band, through=Contract)
class Album(models.Model):
artist = models.ForeignKey(Musician)
name = models.CharField(max_length=100)
release_date = models.DateField()
num_stars = models.IntegerField()
So, I wanted to expose that on the admin page. So far, so good.
Note that our musicians here keep jumping in and out from bands. Some say one of them even had been on over 2 millions bands in his life-time. I don't know, maybe the bands are Whitesnake, Metallica or something.
How should we do that on the Django Admin Page?
I tried using raw_id_fields and apart the fact I didn't like the effect, it didn't work so well. It took a lot of time to load and it didn't let me add more ids. Weird.
I've used admin.StackedInline with no luck cause it will try to load every contract in a which, well, it's gonna take only 2 thousand years.
When Musician had a direct relation to Band it worked just fine with this library. But now that the relation isn't an straight one. Looks like autocomplete doesn't support it(it was getting slow anyway).
So, with all of this, I ask you lord SO members. What's the best way to do this? Is it autocomplete? Someone must have had to come across this issue!
Thanks in advance.
To avoid loading every bands in your admin page use autocomplete_fields Django doc.
Just use it like that in your admin.py.
autocomplete_fields = ('bands',)
Then no bands will be pulled from DB to front, but you will be able to select it through a Select2 search field and it will be printed as "tags".
I found this solution and hope it will help somebody in the same situation:
I have many to many relations between the Product and Characteristic model.
So, in the admin.py I am setting a form for a Product like the following where catch/get all the Characteristics and make the "prefecth_related" for Characteristic, as well the "select_related" could be done there:
class ProductAdminForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['characteristics'].queryset = Characteristic.objects.prefetch_related('category').all()

django: need to design models/forms for a 'multiple level nested' structures

Assume some Company with Employees. There are Name and Contact information bound to each Employee. Each Contact contains Street and Phones fields.
What I want is a page which lists employees within a company. But everything must be listed as forms. Because I want to be able to modify the particular Employee information and the most important - I want to be able to add new Employees (clicking a button "Add new employee" must add a new empty "Employee form"). As well as it must allow to add a new phone number to the existing Employee's Contact information any time.
The data model looks like:
--Company
----Employee1
------Name
------Contact
--------Street
--------Phones
----------Phone1
----------Phone2
----Employee2
------Name
------Contact
--------Street
--------Phones
----------Phone1
----------Phone2
----------Phone3
...
Could someone please help to design Models and Forms for such a task? Your help is very much appreciated. Many thanks!
P.S. Forgot to mention that I want all the data "collected" in the Company object at the end of the day. I mean when I serialize c = Comapany.objects.all()[0] on the back end the entire employee information must be visible, like c.employees[0].contact.phones[0] must be the first employee's first phone number. Thanks.
P.P.S.
That is not the case that I'm just forwarding my project. This is just an hypothetical example I'd created to present the problem. I'm a django newbie and trying to understand how the framework gets things rolling.
I've spent lot of time on this. I've found several ways to go, but no one got me to the end. For instance, a wonderful blog about nested formsets http://yergler.net/blog/2013/09/03/nested-formsets-redux/ helped with forms and rendering. But, it solved only the half of the problem. The data like I mentioned above is not "being collected" into an object. At the end of the day I want to serialize a Company object and save it in yaml format using pyyaml (see my previous post django: want to have a form for dynamically changed sequence data).
Django is perfect with "static" models and forms, ModelForms are awesome. But what if your model needs to be changed dynamically? No standard way to go. Either no appropriate documentation nor I could find a one. Thus, I'd like to hear how experts imagine the solution for such a problem.
Try this:
from django.db import models
class _Contact(object):
pass
class Company(models.Model):
name = models.CharField(max_length=255)
created_at = models.DateTimeField(auto_now_add=True)
#property
def employees(self):
return self.employee_set.prefetch_related('phones').order_by('-created_at')
class Phone(models.Model):
number = models.CharField(max_length=255)
created_at = models.DateTimeField(auto_now_add=True)
class Employee(models.Model):
name = models.CharField(max_length=255)
street = models.CharField(max_length=255)
phones = models.ManyToManyField('Phone', through='EmployeePhone', blank=True)
created_at = models.DateTimeField(auto_now_add=True)
company = models.ForeignKey(Company)
#property
def contact(self):
_contact = _Contact()
_contact.street = self.street
_contact.phones = self.phones.order_by('-employeephone__created_at')
return _contact
class EmployeePhone(models.Model):
employee = models.ForeignKey(Employee)
phone = models.ForeignKey(Phone)
created_at = models.DateTimeField(auto_now_add=True)
However, you should just use employee.street and employee.phones. employee.contact is redundant.

How do I store multiple values in a single attribute

I don't know if I'm thinking of this the right way, and perhaps somebody will set me straight.
Let's say I have a models.py that contains this:
class Order(models.Model):
customer = models.foreignKey(Customer)
total = models.charField(max_length=10)
has_shipped = models.booleanField()
class Product(models.Model):
sku = models.charField(max_length=30)
price = models.charField(max_length=10)
Now, obviously an order would contain products and not just a product. What would be the best way to add products to an order? The only way I can think is to add another field to 'Order' called 'products', and fill it with a CSV with a sku for each product in it. This, for obvious reasons is not ideal, but I'm not very good at this stuff yet and have no idea of what the better way is.
(keep in mind this is pseudo code, so don't mind misspellings, etc.)
What you're after is a many to many relationship between product and order.
Something like:
class Order(models.Model):
customer = models.foreignKey(Customer)
total = models.charField(max_length=10)
has_shipped = models.booleanField()
products = models.ManyToManyField(Product)
see the docs here and here.
You can create one more model which will serve as many-to-many relationship between Order and Products
something like this
class OrderProducts(models.Model)
product = models.ForeignKey(Product)
order = models.ForeignKey(Order)
I don't recommend using ManyToMany field because prices needs to be saved as char field for future reference.
Make two models:
Order
With: Order number, customer details, date created, payment details
2.OrderItem
With : Product, Price, Quantity, Discount, SKU
And use OrderItem as inline in Order model

Categories