Accessing model field in ManyToMany relation in Django - python

I am following the example in the documentation: https://docs.djangoproject.com/en/3.2/topics/db/models/#extra-fields-on-many-to-many-relationships
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __str__(self):
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
In this case, given a Person object, how can I access all the groups that Person is in?

You access these with:
Group.objects.filter(members=my_person_object)

Related

Retrieve query from django ORM

I created a Company in my django app, two or more person can login with the same company. I want to show the data of one user of the company to the other user of the company.
To simplify: If user1 of a company creates an object, then it should be visible to all the users of that company
Models.py
class User(AbstractUser):
is_employee = models.BooleanField(default=False)
is_client = models.BooleanField(default=False)
class Company(models.Model):
company_name = models.CharField(max_length=255, default=0)
company_email = models.EmailField(max_length=255, default=0)
company_phone = models.CharField(max_length=255, default=0)
def __str__ (self):
return self.company_name
class Employee(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
company = models.ForeignKey(Company, on_delete=models.CASCADE, related_name='comapany_owner')
def __str__ (self):
return self.user.username
class Product(models.Model):
product_name = models.CharField(max_length=255, default=0)
product_priceperunit = models.IntegerField(default=0)
product_owner = models.ForeignKey(Employee, on_delete=models.CASCADE, related_name='product_owner')
Views.py
#method_decorator([login_required, employee_required], name='dispatch')
class ProductsTableView(ListView):
model = Product
context_object_name = 'product'
template_name = 'packsapp/employee/employeeProductsTable.html'
def get_queryset (self):
queryset = Product.objects.filter(product_owner=self.request.user.employee)
return queryset
Here I am extracting the data by employee. How can I modify the query to give the data of all the employee of the same company ??
If that means that the product_owner of that Product belongs to the same company as the compnay of that employee, we can filter with:
#method_decorator([login_required, employee_required], name='dispatch')
class ProductsTableView(ListView):
# ...
def get_queryset (self):
return Product.objects.filter(
product_owner__company=self.request.user.employee.company
)

Roles in django model

I have a model in django, in which there will be several roles - regular user, admin and manager. Each of them will be able to do something else. Is the following model OK to work correctly?
class Team(models.Model):
name = models.CharField('Name', max_length=128)
users = models.ManyToManyField(User)
admins = models.ManyToManyField(User)
managers = models.ManyToManyField(User)
def __str__(self):
return self.name
This might work. If the number of roles is large, or dynamic (as in roles can be added, removed, renamed, updated). You could introduce a ternary relation, like:
from django.conf import settings
class Role(models.Model):
name = models.CharField(max_length=128)
class Team(models.Model):
name = models.CharField('Name', max_length=128)
members = models.ManyToManyField(settings.AUTH_USER_MODEL, through='Membership')
def __str__(self):
return self.name
class Membership(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
team = models.ForeignKey(Team, on_delete=models.CASCADE)
role = models.ForeignKey(Role, on_delete=models.PROTECT)

relationships in django 2 models.py

I want to define a relationship between Book and Member through Borrow in models.py
ER
But I don't know how to define the Borrow relationship.
In the Borrow table it must be determined which books have been borrowed by who and which books have been returned on which date. Should I use another table for this date field?
models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils.translation import gettext as _
class CategoryType(models.Model):
category_name = models.CharField(max_length=200)
def __str__(self):
return self.category_name
class Book(models.Model):
name = models.CharField(verbose_name="عنوان", max_length=128)
number_of_copy = models.IntegerField(default=0)
writer = models.CharField(max_length=64)
B_category = models.ForeignKey(CategoryType, on_delete=models.CASCADE)
class Meta:
ordering = ["B_category"]
def __str__(self):
return self.name
class Borrow(models.Model):
borrowed_from_date = models.DateField(_("borrow Date"), default=0)
borrowed_to_date = models.DateField(_("return Date"), default=3)
actual_return_date = models.DateField()
borrowed_by = models.ForeignKey(member, on_delete=models.CASCADE)
books = models.ManyToManyField(Book)
def __str__(self):
return self.id
class Member(AbstractUser):
pass
I think in the Member class I should have a field containing borrow_id, but how?
It seems to me that you need to use a ManyToMany relationship with a through model (this way you can store extra information for every row of the Borrow model)
...
class Borrow(models.Model):
borrowed_from_date = models.DateField(_("borrow Date"), default=0)
borrowed_to_date = models.DateField(_("return Date"), default=3)
actual_return_date = models.DateField()
borrowed_by = models.ForeignKey(Member, on_delete=models.CASCADE)
book = models.ForeignKey(Book)
def __str__(self):
return self.id
...
class Member(AbstractUser):
borrowed_books = models.ManyToManyField(Book, through='Borrow')
Maybe this link (https://docs.djangoproject.com/es/2.1/ref/models/fields/#django.db.models.ManyToManyField.through) could clarify it more.

Add m2m-through relation from two different classes to the same model

I have an existing applicaton where I have to change a regular m2m relationship to a through relation.
I need the ability to add extra parameters to the relation.
My problem is that I need to do it in two places.
This is the standard through example.
class Person(models.Model):
name = models.CharField(max_length=255)
class Group(models.Model):
name = models.CharField(max_length=255)
members = models.ManyToManyField(Person, through='Membership')
class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)
I have another model that needs a m2m relation to Membership. My suggestion is the following.
class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group, null=True, blank=True)
another_group = models.ForeignKey(AnotherGroup, null=True, blank=True)
class AnotherGroup(models.Model):
name = models.CharField(max_length=255)
members = models.ManyToManyField(Person, through='Membership')
It bugs me that I have to have one field that is null for every instance, or is this my only option?
Another option is using content type in through table.
https://docs.djangoproject.com/en/1.9/ref/contrib/contenttypes/#generic-relations
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
class Membership(models.Model):
person = models.ForeignKey(Person)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')

How to make two Django models with cross relationship?

I need two Django models: first with Users, second with Projects.
Between them I need many-to-many relationship with an additional field(s).
How to make the below code working?
from django.db import models
class User(models.Model):
name = models.CharField('Name', max_length=50)
projects = models.ManyToManyField(Project, through='UserProjects')
def __str__(self):
return self.name
class Project(models.Model):
name = models.CharField('Name', max_length=50)
users = models.ManyToManyField(User, through='UserProjects')
def __str__(self):
return self.name
class UserProjects(models.Model):
user = models.ForeignKey(User)
project = models.ForeignKey(Project)
is_active = models.BooleanField('Active')
At the end User.projects should return Projects for specified User
and in the same way Project.users should return Users for specified Project.
There's no need to put the m2m field on both sides
Jussi pick one, and Django will automatically create a reverse relationship for the other direction.
from django.db import models
class User(models.Model):
name = models.CharField('Name', max_length=50)
def __str__(self):
return self.name
class Project(models.Model):
name = models.CharField('Name', max_length=50)
users = models.ManyToManyField(User, through='UserProjects', related_name='projects')
def __str__(self):
return self.name
class UserProjects(models.Model):
user = models.ForeignKey(User)
project = models.ForeignKey(Project)
is_active = models.BooleanField('Active')
Here is the simplest solution in my opinion:
from django.db import models
class User(models.Model):
name = models.CharField('Name', max_length=50)
class Project(models.Model):
name = models.CharField('Name', max_length=50)
class UserProjects(models.Model):
user = models.ForeignKey(User, related_name='projects')
project = models.ForeignKey(Project, related_name='users')
is_active = models.BooleanField('Active')
In above User.projects returns Projects for specified User and also Project.users returns Users for specified Project.

Categories