Django: How do I get referenced objects in a symmetric ManyToMany relationship? - python

I've created a Many-to-Many relationship for the model UserProfile, to enable users to grant access to a particular feature to one another. The relationship works as expected with the use of symmetrical=False to ensure a user access is one-way.
Model
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
phone = models.IntegerField(blank=True, null=True)
image = models.ImageField(upload_to='profile_image', default="default_thumbnail.jpg")
department = models.ForeignKey(DepartmentModel, on_delete=models.SET_NULL, null=True)
allow_booking_access = models.ManyToManyField("self", blank=True, symmetrical=False)
def __str__(self):
return self.user.username
class UserInline(admin.StackedInline):
model = UserProfile
can_delete = False
verbose_name_plural = 'UserAccounts'
class UserAccount(BaseUserAdmin):
inlines = (UserInline,)
I am able to query the users that a particular user wants to grant access to via: (for example id=1)
UserProfile.objects.get(id=1).allow_booking_access.all()
However, I would like to retrieve the users that have granted access to the particular user.
How would I do this?
Additional Information
Using Relation
Database Information

You can filter with:
UserProfile.objects.filter(allow_booking_access=my_user)
With your sample data, it will return the UserProfile with id=7 for this query.
or if you want to query in reverse:
UserProfile.objects.filter(userprofile=my_user)
With your sample data, it will return the UserProfiles with id=7, id=3, user=4 and user=7 for this query.

Related

Django: Filter records based on one to many relationship

I have following models,
class User(models.Model):
name = models.CharField(max_length=255)
...
class InsuranceProfile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
...
class ProductExpertiseMaster(models.Model):
class Meta:
db_table = 'product_expertise_master'
name = models.CharField(max_length=255)
main_category = models.CharField(max_length=255)
class UserProductExpertise(models.Model):
user = models.ForeignKey(User, on_delete=models.DO_NOTHING)
product_expertise = models.ForeignKey(ProductExpertiseMaster, on_delete=models.DO_NOTHING)
So what I am trying to do is I want to filter records based on various fields some of the belong to User model & some of them belong to the InsuranceProfile model.I am filter the records based on User & InsuranceProfile model which is working fine. Now i want to add one more filter which will be based on the UserProductExpertise model.I want to get all the InsuranceProfiles with User details who have some matching condition with product expertise entries in UserProductExpertise model. Any help would appreciated.
You can try like this using __isnull:
InsuranceProfile.objects.filter(user__userproductexpertise__isnull=False)
It will return all the users who has an entry in in UserProductExpertise model. For querying, you need to use all lowercase of the model name, (ie userproductexpertise) and add __isnull at the end of it.
I think you should make some changes in your models before proceeding further.
UserProductExpertise model is the bridge table between ProductExpertiseMaster and User, which provides a many-to-many relationship. If you won't add additional fields to UserProductExpertise model, you can drop it and define user relation in ProductExpertiseMaster model.
If you prefer using seperate model for this relationship, on_delete=models.DO_NOTHING is prone to errors, you can change it to models.CASCADE
Here is an example with many-to-many relation:
class User(models.Model):
name = models.CharField(max_length=255)
class InsuranceProfile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
content = models.CharField(("Content"), max_length=500)
class ProductExpertiseMaster(models.Model):
class Meta:
db_table = 'product_expertise_master'
name = models.CharField(max_length=255)
main_category = models.CharField(max_length=255)
user = models.ManyToManyField(User, verbose_name=("Users"), related_name="expertises")
For filtering your query:
InsuranceProfile.objects.filter(user__expertises__isnull=False)

Is there any way to select a value dynamically for a model's related field in runtime?

I want to achieve a functionality, where I need to select a django model (e.g from a drop down list), and after selecting one, all the objects of that model shows up.
class Thread(models.Model):
sender = models.(???) # This need to be a field that can store a different model on a run time.
receiver = models.(???) # same here.
Is there any way that I can dynamically first select the model and then pick an object of that list. I have seen this functionality in odoo. But is there anything in Django?
Use Inheritance for in your Model and map your foreign key to User, and then pass either a teacher of student object.
You can use the many-to-many filed with multiple available choices of "Student" and "Teacher" from another Model.
class UserRole(models.Model):
STUDENT = 'STUDENT'
TEACHER = 'TEACHER'
ROLE_CHOICES = (
(STUDENT, 'student'),
(TEACHER, 'teacher'),
)
role_name = models.CharField(max_length=255, choices=ROLE_CHOICES)
def __str__(self):
return "{}".format(self.role_name)
class User(AbstractUser):
username = models.CharField(max_length=50, unique=True)
email = models.EmailField(_('email address'))
role = models.ManyToManyField(UserRole)
Class Thread(models.Model):
sender = models.OneToOneField(User, on_delete=models.CASCADE)
receiver = models.OneToOneField(User, on_delete=models.CASCADE)
This way you can only put available roles in sender and receiver fields of Thread.
The solution was possible with ajax too, but there also is another way in django which I was searching for.
class Test(models.Model):
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
Have a good one.

Django Multiple-User Model

I need advice on a multiple user type.
Scenario:
A user can be an organization, where in this organization they can place adverts on the website. The owner of this organization(user) can edit/delete users and adverts of his own organization(group). In this organization user type there are users that also can log in and they can only see the adverts placed by them, but the owner of this group must see all adverts of his own and of his users. Think like an estate listing where an organization has multiple locations/users that can place adverts, and has to be managed by a admin user of this organization.
What type or model is the best/cleanest for implementing this in a good way? Do I need the Django's User and Group model?
One solution would be to have the "User Profiles" structure.
So you use the standard Django User Model and you attach to it several OneToOne relationships depending on the number of profile types you'll have. This has the advantage of allowing users to cover more than one role at the same time.
For example:
from django.contrib.auth.models import User
class Organization(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="organization")
name = models.CharField(max_length=50, blank=True, null=True)
class Supervisor(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="supervisor")
name = models.CharField(max_length=50, blank=True, null=True)
organization = models.ForeignKey(Organization, on_delete=models.CASCADE, related_name="supervisors")
class CustomUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="custom_user")
name = models.CharField(max_length=50, blank=True, null=True)
supervisor = models.ForeignKey(Supervisor, on_delete=models.CASCADE, related_name="custom_users", blank=True, null=True)
And then when you go and create the models for the ads to be displayed on the website you can use the built-in PermissionRequiredMixin.
In order to do that you have to start by adding "permissions" in the ad model Meta class:
class Ad(models.Model):
# fields
class Meta:
permissions = [
('can_edit_ads', 'org_representative')
]
Then on your view you have to extend the PermissionRequiredMixin, example:
class EditAd(UpdateView, PermissionRequiredMixin):
model = Ad
template_name = "ad123.html"
permission_required = "ad.can_edit_ads"
A quick way to test it is by going in the user table on the admin panel, open a user detail page where you can see all the permissions, and there alongside the others you'll find your custom one as well.
From there you can easily assign the new permission to the specific user.

Django Following Table

How can i alter my code so that the user logged is not able to follow themselves. I tried unique_together but could not get it to work
I will be using a button on other users profile pages to add the user to the logged in users following list in this table.
class FollowList(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
following = models.ManyToManyField(User, related_name='followers')
I'd suggest you use something like intermediary model. ManyToMany in fact is a model with two ForeignKey fields: first is for your FollowList model and second is for linking the User instance. So you have an extra relation to your model. Better way:
class Follow(models.Model):
follower = models.ForeignKey(User, on_delete=models.CASCADE, related_name='my_following_users')
following = models.ForeignKey(User, on_delete=models.CASCADE, related_name='my_followers')
class Meta:
unique_together = (
('follower', 'following'),
)
def save(self, *args, **kwargs):
if self.follower.pk != self.following.pk: # preventing of following themselves
return super().save(*args, **kwargs)
# use like this
dev YourView():
Follow.objects.create(follower=request.user, following=user)
UPD:
If you need to set multiple followers with once request, do something like this:
dev YourView():
items = []
for uid in ("<user ids here>"):
items.append(Follow(follower=request.user, following__pk=uid))
Follow.objects.bulk_create(items)

Django 2 Many to Many relationships

I'm working on a project using Python(3.7) and Django(2.1) in which I need to build a relationship between users and organizations.
I'm using the default Django User model and a profile model to add extra information to users.
Many users can join an organization and an Organization can have many members, a user can create an Organization, these behaviors I need to implement, according to my understanding we need to build a ManyToMany relationship for Organizations model, but don know how to use this relationship to display the information, e.g display a user's organizations on his profile page.
Here are my models:
class Organization(models.Model):
name = models.CharField(max_length=255, blank=False)
users = models.ManyToManyField(User, related_name='members', null=True)
def __str__(self):
return self.name
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='media/default.jpg', upload_to='profile_pics')
goals = MultiSelectField(choices=goals_choices, default='')
def __str__(self):
return f'{self.user.username} Profile'
You can get all organizations of a particular user by:
my_user.members.all()
If you want to access from profile:
my_profile.user.members.all()
But I would suggest to remove related_name or rename it. If you remove it you can access all user organizations as:
my_user.organization_set.all()
my_profile.user.organization_set.all()
For organization you can get all users by:
my_org.users.all()

Categories