I have a class based view:
class PostListViewMojeReported(ListView):
def get_username(self, **kwargs):
login_username = request.user.username
context = {'login_username': login_username}
return context
model = Post
template_name = 'blog/filter_moje_reported.html'
context_object_name = 'posts'
queryset = Post.objects.filter(Q(status='Otvorena') & (Q(res_person_1_username=username) | Q(res_person_2_username=username)))
ordering = ['-date_posted']
paginate_by = 30
I don't know how to get username from the current logged in user to use as a filter in my queryset. I need to compare the current logged in user with 'res_person_1_username' and 'res_person_2_username'.
You can obtain the requerst object with self.request, so:
class PostListViewMojeReported(ListView):
model = Post
template_name = 'blog/filter_moje_reported.html'
context_object_name = 'posts'
paginate_by = 30
def get_username(self, **kwargs):
login_username = self.request.user.username
context = {'login_username': login_username}
return context
def get_queryset(self, *args, **kwargs):
username = self.request.user.username
return super().get_queryset(*args, **kwargs).filter(
Q(res_person_1_username=username) | Q(res_person_2_username=username),
status='Otvorena'
).order_by('-date_posted')
I would however advise to work with two ForeignKeys to the user model, and not store the username, since it is possible that later the user removes their account, and another person then creates an account with that username.
Related
I want to create pege which previews auhors profile and posts with Django.
I created UserPostListView Class, then I want to search on Profile model by author's name and get profile.
How can I do this?
All code here
models.py
class Profile(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE)
image = models.ImageField(default='default.jpg',upload_to='profile_pics')
def __str__(self):
return f'{self.user.username} Profile'
def save(self):
super().save()
img = Image.open(self.image.path)
output_size = (300,300)
img.thumbnail(output_size)
img.save(self.image.path)
views.py(UserPostListView Class)
class UserPostListView(ListView):
model = Post
template_name = 'blog/user_posts.html'
context_object_name = 'posts'
paginate_by = 5
def get_queryset(self):
user = get_object_or_404(User, username=self.kwargs.get('username'))
return Post.objects.filter(author=user).order_by('-date_posted')
def get_context_data(self, **kwargs):
context = super(UserPostListView, self).get_context_data(**kwargs)
context['profiles'] = Profile.objects.all()
return context
If I understand, you want the author profile of the posts which are in your post queryset that is a single user, so in your get_context_data you can get author for each post.
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["profile"] = Profile.objects.filter(user__username=self.kwargs.get("username"))
return context
My code:
models.py
class EmployeeManager(models.Manager):
def get_queryset(self):
return super().get_queryset().exclude(employed=False)
class NotEmployedEmployee(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(employed=False)
class Employee(models.Model):
objects = EmployeeManager()
not_employed = NotEmployedEmployees()
name = models.CharField(max_length=250)
employed = models.BooleanField(default=True, blank=True, null=True)
views.py
class EmployeeListView(ListView):
model = Employee
template_name = 'tmng/employee_list.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
resultset = EmployeeFilter(self.request.GET, queryset=self.get_queryset())
context['filter'] = resultset
return context
class EmployeeUpdateView(UpdateView):
template_name = 'tmng/employee_update.html'
model = Employee
fields = '__all__'
def form_valid(self, form):
self.name = form.cleaned_data.get('name')
return super().form_valid(form)
def get_success_url(self):
messages.success(self.request, f'Employee "{self.name}" changed!')
return '/'
For all my currently working employees my list and update view works fine.
But I also want a list/update-view for my not-employed employees so I can 'reactivate' them once they rejoin the company.
For the list view I found a semi-solution by using a function based view.
views.py
def not_employed_employee_list_view(request, *args, **kwargs):
template_path = 'tmng/employee_not_employed.html'
context = {'employees': Employee.not_employed.all()}
return render(request, template_path, context)
So what I'm looking for is a way to see list/update non employed employees. Is there a way to say to class based / functions views to use not the default employees but the 'non_employed' employees?
I did not create new templates, but just created a new class based list view
class EmployeeNotEmployedListView(EmployeeListView, ListView):
def get_queryset(self):
return Employee.not_employed.all()
And for the update view, I updated the default Employee update view
class EmployeeUpdateView(UpdateView):
template_name = 'tmng/employee_update.html'
model = Employee
fields = '__all__'
def get_queryset(self):
return Employee.objects.all() | Employee.not_employed.all()
def form_valid(self, form):
self.name = form.cleaned_data.get('name')
return super().form_valid(form)
def get_success_url(self):
messages.success(self.request, f'Employee "{self.name}" changed!')
return '/'
Is there a way to return a dictionary through the get_queryset function of a class based view in Django? I want to pass the array tickets and the string email to my template, but I am only able to pass tickets right now.
Content of views.py:
class UserTicketListView(ListView):
model = Ticket
template_name = 'ticket_system/user_tickets.html'
context_object_name = 'tickets'
ordering = ['-date_posted']
paginate_by = 5
def get_queryset(self):
user = get_object_or_404(User, username=self.kwargs.get('username'))
email = User.objects.get(username=user).email
return Ticket.objects.filter(author=user).order_by('-date_posted')
class UserTicketListView(ListView):
model = Ticket
template_name = 'ticket_system/user_tickets.html'
context_object_name = 'tickets'
ordering = ['-date_posted']
paginate_by = 5
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
queryset = self.get_queryset()
user = get_object_or_404(User, username=self.kwargs.get('username'))
email = User.objects.get(username=user).email
queryset = queryset.filter(author=user).order_by('-date_posted')
context['user'] = user
context['email'] = email
return context
I'm working on a project with some social features and need to make it so that a User can see all details of his profile, but only public parts of others' profiles.
Is there a way to do this within one ViewSet?
Here's a sample of my model:
class Profile(TimestampedModel):
user = models.OneToOneField(User)
nickname = models.CharField(max_length=255)
sex = models.CharField(
max_length=1, default='M',
choices=(('M', 'Male'), ('F', 'Female')))
birthday = models.DateField(blank=True, null=True)
For this model, I'd like the birthday, for example, to stay private.
In the actual model there's about a dozen such fields.
My serializers:
class FullProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
class BasicProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = read_only_fields = ('nickname', 'sex', 'birthday')
A custom permission I wrote:
class ProfilePermission(permissions.BasePermission):
"""
Handles permissions for users. The basic rules are
- owner and staff may do anything
- others can only GET
"""
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
else:
return request.user == obj.user or request.user.is_staff
And my viewset:
class RUViewSet(
mixins.RetrieveModelMixin, mixins.UpdateModelMixin,
mixins.ListModelMixin, viewsets.GenericViewSet):
"""ViewSet with update/retrieve powers."""
class ProfileViewSet(RUViewSet):
model = Profile
queryset = Profile.objects.all()
permission_classes = (IsAuthenticated, ProfilePermission)
def get_serializer_class(self):
user = self.request.user
if user.is_staff:
return FullProfileSerializer
return BasicProfileSerializer
What I'd like is for request.user's own profile in the queryset to be serialized using FullProfileSerializer, but the rest using BasicProfileSerializer.
Is this at all possible using DRF's API?
We can override the retrieve() and list methods in our ProfileViewSet to return different serialized data depending on the user being viewed.
In the list method, we serialize all the user instances excluding the current user with the serializer returned from get_serializer_class() method. Then we serialize the current user profile information using the FullProfileSerializer explicitly and add this serialized data to the data returned before.
In the retrieve method, we set a accessed_profile attribute on the view to know about the user the view is displaying. Then, we will use this attribute to decide the serializer in the get_serializer_class() method.
class ProfileViewSet(RUViewSet):
model = Profile
queryset = Profile.objects.all()
permission_classes = (IsAuthenticated, ProfilePermission)
def list(self, request, *args, **kwargs):
instance = self.filter_queryset(self.get_queryset()).exclude(user=self.request.user)
page = self.paginate_queryset(instance)
if page is not None:
serializer = self.get_pagination_serializer(page)
else:
serializer = self.get_serializer(instance, many=True)
other_profiles_data = serializer.data # serialized profiles data for users other than current user
current_user_profile = <get_the_current_user_profile_object>
current_user_profile_data = FullProfileSerializer(current_user_profile).data
all_profiles_data = other_profiles_data.append(current_user_profile_data)
return Response(all_profiles_data)
def retrieve(self, request, *args, **kwargs):
self.accessed_profile = self.get_object() # set this as on attribute on the view
serializer = self.get_serializer(self.accessed_profile)
return Response(serializer.data)
def get_serializer_class(self):
current_user = self.request.user
if current_user.is_staff or (self.action=='retrieve' and self.accessed_profile.user==current_user):
return FullProfileSerializer
return BasicProfileSerializer
I managed to hack together the solution that provides the wanted behaviour for the detail view:
class ProfileViewSet(RUViewSet):
model = Profile
queryset = Profile.objects.all()
permission_classes = (IsAuthenticated, ProfilePermission)
def get_serializer_class(self):
user = self.request.user
if user.is_staff:
return FullProfileSerializer
return BasicProfileSerializer
def get_serializer(self, instance=None, *args, **kwargs):
if hasattr(instance, 'user'):
user = self.request.user
if instance.user == user or user.is_staff:
kwargs['instance'] = instance
kwargs['context'] = self.get_serializer_context()
return FullProfileSerializer(*args, **kwargs)
return super(ProfileViewSet, self).get_serializer(
instance, *args, **kwargs)
This doesn't work for the list view, however, as that one provides the get_serializer method with a Django Queryset object in place of an actual instance.
I'd still like to see this behaviour in a list view, i.e. when serializing many objects, so if anyone knows a more elegant way to do this that also covers the list view I'd much appreciate your answer.
I am trying to log the activities during save operation to track all the changes to user model. my approach is as follows.
class User(AbstractUser):
undergrad_college = models.CharField(max_length=20, choices=COLLEGE_CHOICES)
undergrad_degree = models.CharField(max_length=20, choices=COLLEGE_DEGREES)
postgrad_college = models.CharField(max_length=20, choices=COLLEGE_CHOICES)
postgrad_degree = models.CharField(max_length=20, choices=COLLEGE_DEGREES)
currently_working_on = models.TextField()
previous_work_experience = models.TextField()
previous_internship_experience = models.TextField()
def __str__(self):
return self.username
def save(self, *args, **kwargs):
Log(user=User, actions="Updated profile",
extra={"undergrad_college": self.undergrad_college,
"undergrad_degree": self.undergrad_degree,
"postgrad_college": self.postgrad_college,
"postgrad_degree": self.postgrad_degree,
"currently_working_on": self.currently_working_on,
"previous_work_experience": self.previous_work_experience,
"previous_internship_experience": self.previous_internship_experience
})
super(User, self).save(args, **kwargs)
my views are like this for handling the logging.
class ActivityMixin(LoginRequiredMixin):
def get_context_data(self, **kwargs):
context = super(ActivityMixin, self).get_context_data(**kwargs)
context['activities'] = Log.objects.filter(user=self.request.user)
return context
class IndexListView(ActivityMixin, ListView):
template_name = 'pages/home.html'
model = User
I get this error while performing the update action.
Cannot assign "<class 'users.models.User'>": "Log.user" must be a "User" instance.
Update view is as follows
class UserUpdateView(LoginRequiredMixin, UpdateView):
form_class = UserForm
# we already imported User in the view code above, remember?
model = User
# send the user back to their own page after a successful update
def get_success_url(self):
return reverse("users:detail",
kwargs={"username": self.request.user.username})
def get_object(self, **kwargs):
# Only get the User record for the user making the request
return User.objects.get(username=self.request.user.username)
How to assign the User model instance to the Log function. I cant get this working. I am Django newbie.
Looks like pretty straightforward, replace User with self:
Log(user=User, ...
Log(user=self, ...