Django: Create a queryset - python

I have a Friendship model which looks like this:
from_user = ForeignKey(User, related_name='friends')
to_user = ForeignKey(User, related_name='friends_')
I have a manager to get all the Friendship models of a user:
def for_user(self, user):
return self.filter( Q(to_user=user) | Q(from_user=user) )
So now I would like to have a queryset with all the user objects that are friends. I thought of just writing a simple loop and add them to a list but then I lose the ability to write queries. For example for all the friends of a user I would like to filter/get one with a particular username.
The title of my question is a little generic so if anybody knows a better one feel free to change it.

User.objects.filter(Q(friends__to_user=someuser)|Q(friends___from_user=someuser))
No clue if that second Q() will actually work, but that's what you've decided to call the related field.

Related

How to access data across M2M tables in Django?

What is the 'best practice' way of accessing data across a 1 (or more) many-to-many tables?
This is incredibly difficult for me as I am not sure what I shuld be googling/looking up.
I have attached a diagram of my data model. I am able to query data for 'C' related ot a user, by utilizing serializers.
there has to be a simpler way of doing this (I'm hoping).
Doing it with serializers seems incredibly limiting. I'd like to access a user's 'B' and 'C' and transform the object to only have a custom structure and possible unique values.
Any direction is much appreciated. Pretty new to Django, so I apologize for this newb type of question.
Here is an example of M2M relation using Django:
class User(models.Model):
name = models.CharField(...)
class Song(models.Model)
title = models.CharField(...)
users_that_like_me = models.ManyToManyField('User', ..., related_name='songs_that_i_like')
So a User can like many Songs and a Song can be liked by many Users.
To see all the songs a user liked, we can do:
user = User.objects.get(id='<the-user-id>')
liked_songs = user.songs_that_i_like.all()
And to see all the users who like a particular song we can similarly do:
song = Song.objects.get(id='<the-song-id>')
users_that_like_this_song = song.users_that_like_me.all()
Both liked_songs and users_that_like_this_song are actually querysets, meaning we can do some Django magic on them.
For example, to find all users named Jon that liked this song we can do:
users_that_like_this_song.filter(name='Jon')
We can also add some property shortcuts to our Models to help with some common tasks, for example:
class User(models.Model):
...
#property
def number_of_liked_songs(self):
return self.songs_that_i_like.count()
Then we can do:
user = User.objects.get(id='<the-user-id>')
number_of_songs_i_like = user.number_of_liked_songs
There's much more we can do with Django - if you're looking for something specific let us know.

Referencing user object inside model method in Django

I have the following in my model:
class Genre(models.Model):
name = models.CharField(max_length=100)
def my_latest_song(self):
song = Song.objects.filter(genre_id=self.id, author_id=XXXXXXXXX).order_by('-date')
return song[0];
class Song(models.Model):
name = models.CharField(max_length=100)
genre = models.ForeignKey(Genre, on_delete=models.CASCADE, null=True)
date = models.DateField()
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
So with the my_latest_song method I want to obtain for each genre what the latest song is for the user currently logged in. Note: I am already making sure that users MUST be logged in to see this, do not worry about this additional validation.
The question is: how can I pass the user id of the user that is currently logged in onto this model method? Where the XXXXXXXXXX is listed I have tried:
author_id=request.user.id
author_id=user.id
author=request.user
author=user
And many similar options. But I'm new to Django and just not sure about how to properly reference this. Nothing is working yet.
Please note: the issue is that I am constantly (in many different views) displaying the latest song for each genre. So that's why I am thinking it makes sense in the model. It's not stored in a database, it's simply retrieved within the model. Please let me know if this is not appropriate.
For instance, on many pages I am showing a list of genres and for each genre the latest song uploaded by that user:
Genre | Last Song
----------------------
Pop | Song 1
Rock | Song 33
Classic | Song 32
Something like this maybe?
...
def my_latest_song(self, user_id):
song = Song.objects.filter(genre_id=self.id, author=User.objects.get(pk=user_id)).order_by('date')
return song[0];
...
You will not be able to use request.user.id or any other request value in that method, as the model does not actually use requests. That usually is done by a form.
You should not be making this query in your model. It is much better to make the query in views.py whenever you need the information.
Below is, if I understand correctly, what you would need to do to make this query in the view.
def relevant_view(request,genreID_from_url):
# ... #
song = Song.objects.filter(author=request.user).filter(genre=genreID_from_url).order_by('-date')[:1]
# ... #
A couple of points:
I think you would need to pass the genre you are querying for in the URL. Here is a good tutorial for that: http://django-book.readthedocs.io/en/latest/chapter03.html#your-third-view-dynamic-urls . You could also do it using a form - it depends on the circumstances in which the query needs to be made.
You need to order by '-date' and not 'date' so that you get the most recent song at the start of the query.
The [ ] at the end is Django's syntax for limiting a queryset. The above limits it to only the first item of the queryset, as you are attempting to do.
The page in the Django docs for queries is really helpful and clear: https://docs.djangoproject.com/en/2.0/topics/db/queries/

What is the equivalent of None and Null in Django if statements [duplicate]

I have quite a simple problem to solve. I have Partner model which has >= 0 Users associated with it:
class Partner(models.Model):
name = models.CharField(db_index=True, max_length=255)
slug = models.SlugField(db_index=True)
user = models.ManyToManyField(User)
Now, if I have a User object and I have a Partner object, what is the most Pythonic way of checking if the User is associated with a Partner? I basically want a statement which returns True if the User is associated to the Partner.
I have tried:
users = Partner.objects.values_list('user', flat=True).filter(slug=requested_slug)
if request.user.pk in users:
# do some private stuff
This works but I have a feeling there is a better way. Additionally, would this be easy to roll into a decorator, baring in mind I need both a named parameter (slug) and a request object (user).
if user.partner_set.filter(slug=requested_slug).exists():
# do some private stuff
If we just need to know whether a user object is associated to a partner object, we could just do the following (as in this answer):
if user in partner.user.all():
#do something

How to assign Django object ownership without explicitly declaring an owner field on all models?

I'm currently trying to figure out per user object permissions for our Django website API.
I have several models with sensitive information, that I need to be able to filter on a user basis.
For a simplified example of one of the models:
Restaurant, main customer of the website.
User, each user gets assigned a restaurant when the user account is
created. As such, a restaurant can have many users and they all
should only be able to access that restaurant's information.
Oven, which belong to a specific restaurant. A restaurant can have
many ovens.
Recipe, which belong to an oven. An oven can have many different
recipes.
Recipe Results, which belong to a recipe. There can be many different
Recipe Results belonging to the same Recipe (different ingredients
tried, etc).
There are at least 12+ different models. All models from a particular restaurant have to be hidden from other restaurants, we don't want them to be able to look at other restaurant recipes after all!
Not all models have a user = models.ForeignKey(User)
Without having to go into each one of my models and declaring owner = models.ForeignKey(User), is there a way to filter them in my API List Views and Detail Views?
Currently my List API View looks like this (simplified example):
class RecipeResultsListAPIView(ListAPIView):
queryset = RecipeResults.objects.all()
queryset = queryset.prefetch_related('oven')
serializer_class = RecipeResultsListSerializer
filter_backends = (DjangoFilterBackend,)
filter_fields = ('id', 'time', 'oven', 'recipe_name', 'recipe_description')
pagination_class = ExpertPageNumberPagination
def list(self, request):
user = User.objects.get(username=request.user)
restaurant = Restaurant.objects.get(user=user)
ovens = Oven.objects.filter(restaurant=restaurant)
queryset = RecipeResults.objects.filter(oven__in=ovens)
serializer = RecipeResultsListSerializer(queryset, many=True, context={'request':request})
return Response(serializer.data)
And the model for that looks like this:
class RecipeResults(models.Model):
time = models.DateTimeField()
oven = models.ForeignKey(Oven, on_delete=models.CASCADE)
recipe_name = models.CharField(max_length=20)
recipe_description = models.CharField(max_length=50)
def __str__(self):
return str(self.time) + ': ' + self.recipe_name + ' = ' + self.recipe_description
def __key(self):
return self.oven, self.time, self.recipe_name
def __eq__(self, y):
return isinstance(y, self.__class__) and self.__key() == y.__key()
def __hash__(self):
return hash(self.__key())
class Meta:
unique_together=(('time','recipe_name', 'oven-'),)
Specifically looking at the modified list method, currently this works properly to filter API call results to display only those Recipe Results that belong to the user that is logged in.
What I'm trying to figure out is if there's an easier way to do this, as for each model I would have to trace back ownership to the specific restaurant which would get confusing fast as I have 12+ different models.
What I'm not sure is if declaring "owner = models.ForeignKey(User)" on each of those models is the way to go. It feels like it would create many extra steps when retrieving the data.
I have also tried
class IsOwnerOrAdmin(BasePermission):
"""
Custom permission to only allow owners of an object to see and edit it.
Admin users however have access to all.
"""
def has_object_permission(self, request, view, obj):
# Permissions are only allowed to the owner of the snippet
if request.user.is_staff:
return True
return obj.user == request.user
But this didn't seem to filter properly, and besides, not all of the models have a user field assigned to them.
Please keep in mind I'm a junior developer and I'm learning a lot as I go. I'm only working on the API side of the company. The website and schema is already a work in progress and other systems depend on it, and so I'm trying not to modify the schema or models too much (I would like to avoid this if possible, but will do it if it's the only way). I was also brought in just to work on the API at first. The company understands I'm a junior developer and I'm extremely grateful to have been given the opportunity to grow while learning this project, but this one issue seems to be giving me a lot more trouble than actually building the rest of the API for the website.
I would greatly appreciate any help I can get with this!
I think you might benefit from model inheritance in this case.
You can define a base model for your owner-affected objects.
An example can look like:
class OwnedModel(models.Model):
owner = models.ForeignKey(User)
class Meta:
abstract = True
Then you can simply add this as the base for your other models:
class SomeModel(OwnedModel):
"""
This class already has the owner field
"""
A big downside of this approach is that you will still need a migration that will alter every involved table.
If you aren't allowed to do that, you might be able to do it with a loose, non relational approach, for example with django's permission model. You can assign automatically generated permission strings, eg: myapp.mymodel.pkey:
A final alternative is this third party source app that handles things for you: django-guardian

Django Form with a one-to-many relationship

I have a form in Django called PersonForm this forms model has a one-to-many relationship with Car. When displaying the PersonForm just like in the Django Admin I would like to allow my users to select/deselect from a list of Cars etc. Is this possible? I'm looking for information on where to start.
This is what I have so far for the PersonForm:
class PersonForm(forms.ModelForm):
class Meta:
model = Person
fields = ('description',)
The Models:
class Person(models.Model):
description = models.CharField(max_length="150")
class Car(models.Model):
make = models.CharField(max_length="25")
owner = models.ForeignKey('Person', related_name="Car")
So in the person form I need to show a list of cars that person is the owner of an allow selecting/deselecting of them. I'm assuming I can do this in the form i.e. using something like the related name.
Sounds like you want an inline model form. This give you the ability to add/remove Car objects from a Person within the Person form.
That previous link was for inlinemodeladmin. This next link is for an inline form:
https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#modelforms-factory
I didn't have any chance with inline formset, so i would suggest to override your save method of the model, i feel it's more DRY:
class PersonForm(forms.ModelForm):
# add a field to select a car
car = forms.ModelChoiceField(car.objects.all())
class Meta:
model = Person
fields = ('description', 'car')
def save(self, commit=True):
instance = super().save(commit)
# set Car reverse foreign key from the Person model
instance.car_set.add(self.cleaned_data['car']))
return instance
I know this is an old thread, but since I found myself almost exclusively pointed here by google when searching, I thought I would include the following for anyone else looking for an answer.
The answer, I think, is to use
https://docs.djangoproject.com/en/3.1/ref/forms/fields/#modelchoicefield
or
https://docs.djangoproject.com/en/3.1/ref/forms/fields/#modelmultiplechoicefield
There is a good article on how to use the modelmultiplechoicefield at :
https://medium.com/swlh/django-forms-for-many-to-many-fields-d977dec4b024
But it works for one to many fields as well. These allow us to generate a form with multiple choices as checkboxes or similar widgets based upon a related field in a model.

Categories

Resources