Django ORM JOIN's - django

I have a table 'Comments' and inside field the 'user', I would get in addition to the profile Profile in the same query. Currently I have something like that
comments = models.Comment.objects.select_related('author__profile').filter(post=article)
Unfortunately I can not retrieve information about profile, I can only get to it through
comment.author._profile_set_cache
Any ideas to make it look nice like?
comment.author.profile

If the 'author' is from the contrib.auth User model, then you don't have a FK to the UserProfile. It is a "reverse one-to-one". Fortunately, django is able to navigate a reverse one-to-one using "select_related", so the query is actually retrieving the fields (you can check it by using
print models.Comment.objects.select_related('author__profile').filter(post=article).query
The way to get the profile of a user is with the get_profile() method:
print comment.author.get_profile()
As the profile data is already cached (that's why the _profile_set_cache is for), getting the object means no additional query.

Related

Where is ID saved in django ModelAdmin autocomplete_fields?

I am rewriting some administration interface to django 2.2, currently using django autocomplete_fields admin feature. Simply said I have ModelAdmin object OrderAdmin, which has nested TabularInline ProductAdmin: variable-length table of products which might be added to order. Each of these ProductAdmin holders just contains ForeignKey to actual product class, with some other attributes.
Now I wonder: where does django store id - ForeignKey - of item selected with autocomplete field? It doesn't mark OPTION in selectbox as selected, and although there is suspicious hidden input field with #cashregisterproduct_set-0-id on page, it doesn't have any value. Or is there some special way how to access it? I was thinking about adding id to __str__ method of model and parsing, but thats just ugly.
Thanks for tip.
EDIT: to make it 100% clear, where from does django get ForeignKey of object selected through autoselect_field, when creating new object from ModelAdmin?
I got misguided thinking that this is managed by django. Selected data might be accessed by using select2 framework:
selected_value = $('.myselectbox').select2().val();
related: https://stackoverflow.com/a/47451658/16268461

Django rest framework hyperlinkrelatedfield for one table using primary key

I have a table called 'users' and 'location'. Users table has a foreign key that relates to location table. I have a users serializer to get the JSON. What would I do to get the hyperlinks for the users table using its primary key?
In django rest framework documentation, I couldn't find a solution. I tried using hyperlinkrelatedfield. But still I couldn't achieve this. Can someone help me in finding the solution?
Using rest-framework HyperlinkedRelatedField does not work because it was never built to expose the URL of the object being requested. Mainly because since the client already has the url of the user, why send it back again? Nevertheless you can achieve this by doing something like this.
class UserSerializer(serializers.ModelSerializer):
user_url = serializers.SerializerMethodField()
class Meta:
model = User
def get_label_location(self, obj):
return HyperlinkedRelatedField(view_name='user-detail',
read_only=True) \
.get_url(obj, view_name='label-detail',
request=self.context['request'], format=None)
Take note on a few things,
view-name param to the HyperlinkedRelatedField should be based on your url configuration
read-only has to be true since otherwise you'll have to specify the queryset. But since we have the object needed to generate the url we can ignore that.
I've set format param to None but you might want to set it based on your settings.
You can read up about SerializerMethodField here.

Fine tuning Django queryset retrieval

In a Django app of mine, I need to display, for a list of users (called user_ids), their:
username, avatar and score.
The username is retrieved from the User model, whereas avatar and score are present in the UserProfile model (that has a one-to-one field point to the User model, called user).
Currently my approach is to fetch the full objects (see below), even though I just need 3 attributes from the two models.
What's the most efficient way for me to just retrieve just the required fields, nothing else? Now I know i can do:
usernames = User.objects.filter(id__in=user_ids).values_list('username',flat=True)
scores_and_avatars = UserProfile.objects.filter(user_id__in=user_ids).values_list('score','avatar')
However, these give me separate querysets, so I can't iterate over them as a unified object_list and show each user's username, score and avatar in a Django template. So what would be the most efficient, light-weight way to retrieve and put this information together?
Currently, I'm doing the following to retrieve these three fields: queryset = User.objects.select_related('userprofile').filter(id__in=user_ids)
The most efficient way it's use values, your query will look like this:
usernames = User.objects.filter(id__in=user_ids).values('username', 'userprofile__score', 'userprofile__avatar')
This solution will return dictionary, but you can try to use only instead of values, it'll create django model object with specified fields, but if you will try to access not specified field it'll generate additional query.
usernames = User.objects.filter(id__in=user_ids).select_related('userprofile').only('username', 'userprofile__score', 'userprofile__avatar')

OneToOne Field (with user) is returning numbers instead of usernames

I am trying to extend default user model with a profile. I have a model called Profile that has a field called username which has one to one relationship with user.
I serialized this model to obtain a json response (which works) but username field gives integer output.
Normally I would call username.user, but how do I do it with json?
Is there a way to define output of a model field? I looked up in the documentation, but did not find anything relevant (maybe managers?).
Thanks in advance.
You should look into using natural keys

Adding custom variables into the request object in Django Middleware without using request.session

Is there a recommended way to pass a variable to all my views? Namely in my case, I want to pass a UserProfile object that Foreign Keys a django.contrib.auth.models.User object. I find most if not all my views need to pull the UserProfile object and putting it in Middleware seems like the way to go. It seems like I could do something like the following (I've seen a couple of solutions online that suggest it):
request.session['userprofile'] = userprofile_object
I don't like this because if my UserProfile model ever has a non-serializable field, it would break request.session.
If you have the AuthenticationMiddleware enabled, you will have a user object in all your views. To get the profile all you need to do is call user.get_profile in your view. For example, to output the id of the profile, you would do {{ user.get_profile.id }}.
If you would prefer not to call the get_profile function of the user object each time, you can add arbitrary items to your request. You would create a new middleware which would simply set
request.user_profile = request.user.get_profile()
Then just register that middleware in your settings.py and you should be good to go. I have used this method in the past for getting user geolocation data pinned to the request object.
This proposal depends on the assumption that userprofile objects only matter when users are already logged in so you can get the logged in user via request.user.
It should be possible to get the userprofile by travelling the foreignkey key relation in reverse like this:
if request.user.is_authenticated():
request.user.userprofile_object_set.all() #gets all related userprofile objects
else:
#...