How to get value from the different django model in DTL? - python

I am having 3 different models - User, Thread and UserProfile.
User model contains information like ID, First_name and Last_name.
Thread model contains information like
class Thread(models.Model):
first_person = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, related_name='thread_first_person')
second_person = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True,related_name='thread_second_person')
updated = models.DateTimeField(auto_now=True)
and UserProfile model,
class UserProfile(models.Model):
custom_user = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
picture = models.ImageField(default='profile_image/pro.png', upload_to='profile_image', blank=True)
when I am trying to get all the threads from Thread model and pass it from views.py to my HTML template then I can access User model fields like -
{{ thread.second_person.ID}} {{ thread.second_person.First_name}}
But how can I access picture field from UserProfile with the help of custom_user ?

I'm a little confused: you say you have three models User, Thread and UserProfile. But inside your UserProfile model you reference a CustomUser model as the one-to-one relationship for the custom_user field. Then in your Thread model you reference a plain User model as the FKs for the first_person and second_person fields. Do you have 3 models or 4?
Assuming you only have 3 models, and that CustomUser is actually just User, then what you're trying to achieve should be doable. However you may need to change your conventions regarding related names to best practices in order to do so cleanly.
I have set up the models I think you need roughly below, and the code needed to access the relevant parts of each model within the template layer:
#models.py
class User(AbstractBaseUser):
# User Model Code
class Thread(models.Model):
first_person = models.ForeignKey(
User,
on_delete=models.CASCADE,
null=True,
blank=True,
related_name='thread_first_persons' # Note the Plural
)
# Related name for a FK is a one-to-many relationship
# (i.e. 1 User can be first_person on many threads)
# This may not be your desired behaviour, but it is possible on current set-up
second_person = models.ForeignKey(
User,
on_delete=models.CASCADE,
null=True,
blank=True,
related_name='thread_second_persons'
) # As above
updated = models.DateTimeField(auto_now=True)
class UserProfile(models.Model):
user = models.OneToOneField(
User,
on_delete=models.CASCADE
related_name='user_profile'
)
# Note: custom_user is confusing nomenclature.
# The above is best practice for User <> UserProfile 1-to-1 relationships
picture = models.ImageField(
default='profile_image/pro.png',
upload_to='profile_image',
blank=True
)
Now when you want access to the UserProfile from the Thread object, you can do so as follows inside a template:
{{ thread.second_person.user_profile.picture }}
Side Note: in your views.py file, if you are sending just the thread to your template, then to save your database several queries I would optimise with the following select_related parameters:
#views.py
threads = Thread.objects.select_related(
'first_person', 'first_person__user_profile',
'second_person', 'second_person__user_profile'
).all()
thread = Thread.objects.select_related(
'first_person', 'first_person__user_profile',
'second_person', 'second_person__user_profile'
).get(id=id)

Related

Django ManyToMany alternative pros and cons

I was developing a chat system with channels and have this models for a thread (some attributes removed for simplicity's sake):
class Thread(models.Model):
name = models.CharField(max_length=50, null=True, blank=True)
users = models.ManyToManyField('auth.User')
I realized it is also possible to implement it like this:
class Thread(models.Model):
name = models.CharField(max_length=50, null=True, blank=True)
class ThreadUsers(models.Model):
thread = models.ForeignKey(Thread, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
What are the advantages/disadvantages of using one over the other?
All what you do - is the same. For your last example with custom M2M through model you can add M2M declaration users in Thread:
class Thread(models.Model):
name = models.CharField(max_length=50, null=True, blank=True)
# M2M declaration, which use your ThreadUsers
users = models.ManyToManyField('auth.User', through='ThreadUsers' )
class ThreadUsers(models.Model):
thread = models.ForeignKey(Thread, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
Pros:
You create model self
you can change behavior your M2M connection manually.
You can add additional fields in M2M through connection.
You have full control of this model.
Cons:
problem with m2m connections in django admin.
too much additional code, you can get a hard-to-find errors.
some fields/widgets don't want to work with M2M.through.
all was happened is your problem, this is not tested. Auto-through relation is tested in box.
we have in our projects 50/50 M2M-autothrough vs M2M-manualthrough. if I want to have more control on the models and realations - i use custom through.
p.s. in M2M-autothrough case Django created SomethingLikeYourThreadUsers Model and Table automatically.

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

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.

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 drf-nested-routers - model object has no attributed related field

I am creating an API using the drf-nested-routers application for Django Rest Framework. This application is a tracker where users have sessions and tasks. Each user can have three active tasks and can work on each of these tasks in a given session.
My (abbreviated) models are:
#models.py
class User(models.Model):
name = models.Charfield()
class Task(models.Model):
start_date = models.Datefield()
task_title = models.Charfield()
user = models.ForeignKey(User, on_delete=models.CASCADE)
class Session(models.Model):
session_date = models.Datefield()
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='sessions')
task_one = models.ForeignKey(related_name="task_one")
task_one_attempts = models.IntegerField()
task_two = models.ForeignKey(related_name="task_two")
task_two_attempts = models.IntegerField()
I have created the following (abbreviated) Serializers for these models:
#serializers.py
class TaskSerializer(serializers.ModelSerializer):
user = serializers.StringRelatedField(many=False)
class Meta:
model = Task
fields = ('start_date', 'task_title', 'user')
class SessionSerializer(serializers.ModelSerializer):
user = Serializers.StringRelatedField(many=False)
class Meta:
model = Session
fields = ('session_date', 'user', 'task_one', 'task_one_attempts', 'task_two', 'task_two_attempts')
class UserSerializer(models.ModelSerializer):
sessions = SessionSerializer(many=True)
tasks = TaskSerializer(many=True)
sessions = SessionSerializer(many=True)
class Meta:
model = Users
fields = ('name', 'sessions', 'tasks')
I also have my views.py and urls.py set up to do the routing properly.
I can navigate to the sessions and tasks API views just fine. However, whenever I try to navigate to the user view, it throws the following error:
'User' object has no attribute 'tasks'.
What's really interesting, though, is that if I remove 'tasks' and just include sessions, it serializes everything just fine and gives me a nested view of the User's various sessions.
I'm at a loss here and would appreciate any assistance.
I rubber-ducked it with my wife and figured out my problem.
I had 'related_name="sessions"' in my ForeignKey field for user in models.py.
I was missing that information in the ForeignKey field in the task model.
Hopefully someone else stumbles on this and can learn from my mistake.

Django filtering queries with multi-table inheritance

I'm using Django multi-table inheritance to implement a notifications system.
It looks like this:
class Notification(models.Model):
# this allows us to check the type without having to query another table
type = models.CharField(max_length=2, choices=type_choices)
user = models.ForeignKey(User, related_name='+', null=True)
date = models.DateTimeField(default=datetime.now)
read = models.BooleanField(default=False)
class Meta:
ordering = ["-date"]
# Users can comment on items.
class CommentNotification(Notification):
comment = models.ForeignKey(Comment, related_name='+')
class ShareNotification(Notification):
share = models.ForeignKey(Share, related_name='+')
# If user unsubscribes from an item, they will not receive notifications of comments on that item
class UnsubscribeItem(models.Model):
user = models.ForeignKey(User, related_name='+')
item = models.ForeignKey(Item, related_name='+')
class Comment(models.Model):
item = models.ForeignKey(Item, related_name='comments')
user = models.ForeignKey(User, related_name='+')
comment = models.TextField()
If I want to get all notifications for a user, I can simply query the Notification table. But I also want to exclude any CommentNotification entries if the user has unsubscribed from that item (only if there is an UnsubscribeItem with user=request.user and item=comment.item).
The problem of course is the field I want to filter is not on the base class. Is it possible to modify the queryset itself to exclude those entries? Or do I need to exclude them while serializing the collection? (I'm using django-rest-framework to serialize for my API, if that helps.)

Categories