I have a view that I set up that allows me to view all the training for a specific employee profile:
class ManageTrainingView(LoginRequiredMixin, generic.ListView):
login_url = reverse_lazy('users:login')
model = Training
template_name = 'ppm/training.html'
paginate_by = 10
# Get training queryset for specific profile id
def get_queryset(self):
pk = self.kwargs['pk']
return Training.objects.filter(profile_id=pk)
The problem I'm have is that I'm trying to add more training for a specific employee profile using a profile id instead of a user id. In my training.html template this Works
training.html
<li>Add Training</li>
But this doesn't(NoReverseMatch)
<li>Add Training</li>
So my question is what do I need to do in order to add training for a specific employee profile instead of a user? How do I access the profile object that I'm currently on in the template so that profile.id will work?
I found a solution to my problem and I think this is it. If anyone has a better solution please let me know.
What I did was override get_context_data to return the profile id to the template.
def get_context_data(self, **kwargs):
pk = self.kwargs['pk']
context = super(ManageTrainingView, self).get_context_data(**kwargs)
context['profile_id'] = pk
return context
Now I am able to use:
<li>Add Training</li>
Related
I've got a booking class which is related to Customer and Barber models. I can display all bookings using the detail view, however, can't figure out how to display a booking/bookings that a specific barber has. Basically, I want to get a booking or multiple bookings of a barber based on the ID given to the url.
Here is my model:
customer_id = models.ForeignKey(User, on_delete = models.CASCADE,)
barber_id = models.ForeignKey(Barber, on_delete = models.CASCADE)
timeslot = models.DateTimeField('appointment')
def __str__(self):
return f"{self.customer_id} {self.barber_id} {self.timeslot}"
def get_absolute_url(self):
return reverse("model_detail", kwargs={"pk": self.pk})
My view:
class GetBarberBooking(DetailView):
model = Booking
template_name = "barber_booking.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['barber'] = Booking.objects.filter(
id=self.kwargs.get('<str:pk'))
return context
My url path:
path('barber-booking/<str:pk>/', views.GetBarberBooking.as_view(), name='barber-booking'),
You can remove this piece of code:
context['barber'] = Booking.objects.filter(
id=self.kwargs.get('<str:pk'))
And in template just use:
{{ object.barber_id }}
And show all the booking for barber:
{{ object.barber_id.booking_set.all }}
It will show all the the barber. This works because of FK relation between Booking and Barber model. More information can be found in Django documentation. For reverse relation (Many to one), please check this documentation.
FYI, you do not need to create a field name suffix with _id, because Django creates that automatically for you.
Also, if you want to query a Barber, then you should use Barber as the model in the DetailView. Then you can use a similar query mentioned above:
# view
class GetBarberBooking(DetailView):
model = Barber
# template
{{ object.booking_set.all }}
So I have this system where my Post object has a ManyToMany field and it's called Saves. So like for example on Reddit you can save a post. So I got it working and users can save posts, and it adds them to the ManyToMany field. However, I want to filter out these posts and only show the posts where said user is in the ManyToMany field.
Here is my models.py
class Post(models.Model):
author = models.ForeignKey(User,related_name='posts',on_delete=models.CASCADE)
saves = models.ManyToManyField(User,blank=True,related_name='post_saves')
I have the saves field connected to the User model Django provides.
And here is my views.py
class PostSaveRedirect(RedirectView):
def get_redirect_url(self,*args,**kwargs):
pk = self.kwargs.get("pk")
slug = self.kwargs.get("slug")
obj = get_object_or_404(Post,pk=pk,slug=slug)
url_ = obj.get_absolute_url()
user = self.request.user
if user.is_authenticated:
if user in obj.saves.all():
obj.saves.remove(user)
else:
obj.saves.add(user)
return url_
So this is all working fine, it adds the user to the ManyToMany field, but now I want to know how I can filter out posts and only display ones where the user is in the ManyToMany field.
Here is my saved posts view.
class PostSaveListView(ListView):
model = Post
template_name = 'mainapp/post_saved.html'
paginate_by = 10
queryset = models.Post.objects.all()
def get(self,request):
posts = Post.objects.all()
return render(request, self.template_name)
def get_queryset(self):
return Post.objects.filter().order_by('-published_date')
So with Post.objects.all(), how can I change it so it will filter to my needs? This is a similar queryset for a user post list view I have
I have been Googling and reading up the docs and other articles but have not found anything that has been able to show me how to filter a ManyToMany field. Any help would be much appreciated
edit your model like this:
class PostSaveListView(ListView):
model = Post
template_name = 'mainapp/post_saved.html'
paginate_by = 10
-
def get(self,request):
posts = Post.objects.all()
return render(request, self.template_name)
def get_queryset(self):
object_list = Post.objects.filter(saves__in=[self.request.user]).order_by('-published_date').distinct()
return object_list
The easiest and quickest option for you would be to use the filtering option in like this:
def get_queryset(self):
return Post.objects.filter(saves__in=[self.request.user]).order_by('-published_date')
Please notice the list inclusion for the user object, as that option only filters from lists.
You may consider also adding .distinct() call to the filter also to avoid repetition of objects.
In my ListView I would like to filter the data by the current user logged from the context_data in :
views.py
class DashboardListView(LoginRequiredMixin,ListView):
model = Links
template_name = 'dashboard/home.html'
context_object_name ='links_list'
paginate_by = 15
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['dashboard_list']= Dashboard.objects.filter()[:15]
context['todo_list']= Todo.objects.all().order_by('-pk')[:15]
context['todo_complete']= Todo.objects.all().count()
context['PasswordUsername_list']= PasswordUsername.objects.all()
return context
I tried to override with a query_set but it does work only for the links model
Well, you need to filter all those queries.
context['dashboard_list']= Dashboard.objects.filter(user=self.request.user)[:15]
context['todo_list']= Todo.objects.filter(user=self.request.user).order_by('-pk')[:15]
etc - assuming your models all have a user FK field pointing to the User model.
See the answer below it's working but do not forget to add :
def get_queryset(self):
return self.model.objects.filter(user=self.request.user)
To your ListView otherwise the first model will still be shown.
I'm working on a project by using Django 2.06. I have multiple users and they can post and other people can read their post which is very normal. At the user profile page User should see their own post.
this is where I'm stuck, How i can code the queryset then at the profile section user can see only their own post.
code demo
class ProfileView(ListView):
template_name = "profile.html"
queryset = QuickWord.objects.filter()
context_object_name = 'quickword'
def get_context_data(self, **Kwargs):
context = super(ProfileView, self).get_context_data(**Kwargs)
context['addproduct'] = AddProduct.objects.filter()
context['article_view'] = Article.objects.filter()
context['edit'] = Profile.objects.all().last()
return context
I know that I have to use filter value but do not know how to do that.
Thanks
Assuming your have an author field in your Post model, You should do something like this in your views.py
def profile(request):
user_posts = Post.objects.filter(author=request.user)
return render(request, 'path/to/profile.html', {'posts': user_posts})
Of course the above view requires the user to be logged in.
I have three models Person, User and Profile. Profile links a person to a user like this:
class Profile(models.Model):
user = models.OneToOneField(
User,
on_delete=models.CASCADE
)
person = models.OneToOneField(
Person,
on_delete=models.CASCADE
)
In my person detail view I want to get the username through the person selected.
class PersonDetailView(DetailView):
model = Person
template_name = 'people/person_detail.html'
def get_context_data(self, **kwargs):
context = super(PersonDetailView, self).get_context_data(**kwargs)
profile = Profile.objects.filter(person_id=Person.objects.get(pk=self.kwargs['pk']))
# this line is the problem I guess
user = User.objects.get(pk=profile.user.user_id)
context['user_person'] = user
return context
With this code I get the error
'QuerySet' object has no attribute 'user'
Maybe it is a silly question but I'm lost on this.
How do I get the user from The profile filtered from a person?
Thanks in advance, I hope I made mydelf clear enough.
EDIT
I got everything workin with Robert Townley answers, thank you.
The line that says:
profile = Profile.objects.filter(person_id=Person.objects.get(pk=self.kwargs['pk']))
should instead grab the Profile from the queryset:
profile = Profile.objects.get(person_id=Person.objects.get(pk=self.kwargs['pk']))
If you do "filter()" you'll receive a queryset. If you do "get()" you'll receive the only object matching that queryset. You can also do:
profile_queryset = Profile.objects.filter(person_id=Person.objects.get(pk=self.kwargs['pk']))
profile = profile_queryset.first()
Note: Only do this if you're sure that the Profile object exists, or you'll get a DoesNotExist error.
Correct me if I'm wrong, but it looks like you are creating a relation table to connect a Person with a User.
You do not have to create relation tables in django.
Instead you should add a foreignkey
https://docs.djangoproject.com/en/1.11/ref/models/fields/#module-django.db.models.fields.related
As i can see, You can use simple soulution for your logic,
class PersonDetailView(DetailView):
model = Person
template_name = 'people/person_detail.html'
def get_context_data(self, **kwargs):
context = super(PersonDetailView, self).get_context_data(**kwargs)
context['user_person'] = self.request.user
# Just only one action
return context
Looks like you need this:
class PersonDetailView(DetailView):
model = Person
template_name = 'people/person_detail.html'
def get_context_data(self, **kwargs):
user = self.object.profile.user if hasattr(self.object, 'profile') else None
return super(PersonDetailView, self).get_context_data(user_person=user, **kwargs)