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/
Related
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
This will be my first post here so I hope that everything will be correct.
I got some trouble with django, I try to make a little lottery game.
For this game I have one app called bitcoinlottery and in that app 2 models. As for now they look like this:
from django.db import models
from django.utils import timezone
class Lottery(models.Model):
owner = models.ForeignKey('auth.User')
title = models.CharField(max_length=100)
slug = models.SlugField(max_length=110)
max_players = models.IntegerField()
total_players = models.CharField(default=0)
online = models.BooleanField(default=True)
create_date = models.DateTimeField(default=timezone.now)
class Ticket(models.Model):
owner = #this most be related to the user that buy the ticket
lottery_id = #this most be related to the id of the lottery
ticket_id = #a random number
Now I have two problems that I can't figure out.
The first one is how to create the number of tickets related on the Lottery max_players, the max_players will be a number of the maximum players/tickets available.
The second question is there a option to see all the available tickets in a list on the admin page of the lotteries?, and if yes, what is the way to do this.
Thanks for any help.
Have a nice day.
First of all I am not sure if your owner field would work. I don't see any imports for auth package
owner = models.ForeignKey('auth.User')
Firstly I would suggest you look at this post for changing that relation.
Both of your questions need a little bit more clarity regarding what you actually what to achieve. It would be helpful if the Ticket model is also completed.
For the given information its hard to say if that is possible looking there is no relation between both the models.
class Ticket(models.Model):
# This is not required unless you want it for some reason, you can use
# this owner from the lotter_id
owner = #this most be related to the user that buy the ticket
lottery_id = models.ForiegnKey(Lottery)
ticket_id = #a random number
def __str__(self):
return self.lottery_id, function_that_return_max_tickets()
Using the above relation you can write custom functions in the ModelManager, according to your requirement.
Read through the Mangers that Django provides, these can be used to write those functions which would calculate the max number of tickets and return if you like to use them in views.py using ORM.
EDIT: Given responses in comments and answer I tried suggestion and I get some errors when trying to query , also doing the related name query does not get the right results (as seen in comments)
BusinessLocations.objects.all()
Error: QuerySet object has no attribute 'objects' is the error.
In either case, I did a dump of all the tables and see this:
auth_business_permissions', u'auth_permission', u'auth_user', u'auth_user_businesss', u'auth_user_user_permissions', u'django_admin_log',
u'django_content_type', u'django_migrations', u'django_session', u'ipaswdb_address', u'ipaswdb_billing', u'ipaswdb_billing_businesss',
u'ipaswdb_designation', u'ipaswdb_business', u'ipaswdb_business_business_locations', u'ipaswdb_businessinsurances', u'ipaswdb_businessinvoices',
'ipaswdb_businesslocations', u'ipaswdb_businessterm', u'ipaswdb_insurance', u'ipaswdb_insurance_businesss', u'ipaswdb_invoice', u'ipaswdb_employee',
u'ipaswdb_employeeinvoice', u'ipaswdb_employeelocations', u'ipaswdb_employeeterms', u'ipaswdb_specialty']
I have a ipaswdb_business_business_locations and a ipaswdb_businesslocations which seems strange to me, and I wonder if my database is just gunked up?
Original Question:
I have two models a Business and an Employee. I want them both to be aware of each other but not directly but through another model called a 'BusinessesLocation`. I can sort of express this in my models but it doesn't look or feel right. It is like only the employee knows of the businesses, and not vice vice versa.
I had another question opened to try to answer this but the answer was not 100% correct in that it didn't offer for a many to many it was more like a one to many. In this case: An employee can work at many locations (potentially being an employee of many businesses) and a business can have many locations having many employees.
Currently my models work where this shell script works:
someEmployee.business_locations.all()[0].business.business_name
and it works fine, I can get all the locations of a business an employee works at and via that infer the many businesses an employee might work for given the businesses locations.
But I cannot figure out how to go the other way, and find out all the employees a business has working for them and at which locations
My current (wrongish) models are like this:
class Employee(models.Model):
first_name = models.CharField(max_length = 50)
business_locations = models.ManyToManyField('BusinessLocations', through='EmployeeLocations')
class EmployeeLocations(models.Model):
employee = models.ForeignKey('Employee', on_delete=models.CASCADE)
business_location = models.ForeignKey('BusinessLocations', on_delete=models.CASCADE)
created_at=models.DateField(auto_now_add=True)
updated_at=models.DateField(auto_now=True)
def __str__(self):
return self.provider.first_name
class BusinessLocations(models.Model):
address = models.ForeignKey('Address', on_delete= models.SET_NULL, null=True)
business = models.ForeignKey('Business', on_delete=models.CASCADE)
doing_business_as = models.CharField(max_length = 255)
created_at=models.DateField(auto_now_add=True)
updated_at=models.DateField(auto_now=True)
def __str__(self):
return self.doing_business_as
class Business(models.Model):
business_name = models.CharField(max_length=50)
business_locations = I need something here no idea how
Bellow is some pseudo shell code demonstrating how I would like my models to work:
#create a new business location assume business has been created
newLocation = Address(...)
business.business_locations.add(newLocation, doing_business_as='alternative name maybe')
#assume employee exists
#add a new business location to the employee
#when i say selected business the form would have current employee then in its locations
#you'd have to select a business first, and get a list of all that businesses locations and you
#you could add the business location and then select another business with all ITS locations
# and add one there too if you wish
employee.employee_locations.add(selectedBusiness.business_locations[0])
employee.employee_locations.add(anotherSelectedBusiness.business_locations[1])
Below is what I cannot figure out how to do, vice versa...
#now lets see which businesses the employee works for.
for business in employee.business_locations
business.business_name
#and lets see each businesses employees:
for employee in Employee.objects.all()
employee.
?? No idea how to build the models to represent these relationships
I can get an employees business locations just fine, but I cannot get the above examples of getting a list of employees for a business. Not sure what I need to adjust (or methods I might need?) to get this to work like I want in my shell example.
What you're missing is Django's concept of related objects.
When you define a relationship in a model (i.e., a ForeignKey, OneToOneField, or ManyToManyField), instances of that model will have a convenient API to access the related objects.
You can access the related objects both in queries and as a manager attribute on your models. See the examples in the documentation. In your case this would look something like:
# Now lets see which businesses the employee works for:
Business.objects.filter(businesslocations__employee=employee).distinct()
# And let's see each business's employees:
Employee.objects.filter(business_locations__business=business).distinct()
I am trying to get rate of the user who has written the comment.
this is the scenario:
I hold the comment about Something in my hand, I hold the user in my hand who wrote this comment Something. Now I need to know the rate which is given by the user to this Something.
these are my models:
class Rate(models.Model):
of_user_r = models.ForeignKey(User)
of_something_r = models.ForeignKey(Something)
rate = models.IntegerField()
class Comment(models.Model):
of_user_c = models.ForeignKey(User)
of_something_c = models.ForeignKey(Something)
i did: {{comment.of_user_c.of_user_r.rate}}, but I getting nothing in template.
this is the vusual:
I need the rate of this Something which is given by this User.
Yes, your attempt doesn't work because the relationship from User to Rate is backwards. This means you can't do that query directly in the template: you'd need a model method or a template filter that accepts arguments. The basic query syntax would be:
Rate.objects.filter(user=comment.user)
I have following problem:
My application have 2 models:
1)
class ActiveList(models.Model):
user = models.ForeignKey(User, unique=True)
updatedOn = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.user.username
'''
GameClaim class, to store game requests.
'''
class GameClaim(models.Model):
me = models.ForeignKey(ActiveList, related_name='gameclaim_me')
opponent = models.ForeignKey(ActiveList, related_name='gameclaim_opponent')
In my view I took all ActiveList objects all = ActiveList.objects.all() and passed it to the template
In template I am looping through every item in the ActiveList, and create an xml file which is used on my client application.
the question is:
How can I query the info about the claims which one user (e.g. test, part of ActiveList), made to the user who is under loop
user2 e.g is taken like this
{% for item in activeList %}
{% endfor %}
user 2 is an item in this case
What you are looking at doing belongs more properly in the view than the template. I think you want something like:
claimer = User.objects.get(name='test')
claimed_opponents = User.objects.filter(gameclaim_opponent__me__user=claimer)
Then you can pass those into your template, and operate on them directly.
You might also look at rethinking how your tables relate to one another. I think claims should probably go directly between users, and whether a given user is active should be external to the relationship. I would think a user should be able to claim a game with an inactive user, even if they have to wait for the user to reactivate before that game can begin.
I'm not sure I entirely understand your question, but I think the information you're looking for might be here: http://docs.djangoproject.com/en/dev/topics/db/queries/
Perhaps you could clarify the question if you don't find an answer there?