Obtaining data from user - django

How do I obtain the field data from a User auth query within a class View. It's on the django 2.2.x framework using Python3
This code works just fine...
from django.contrib.auth.models import User
class PaymentsReportView(ListView):
template_name = 'payments/Payment_list.html'
userid = 'James'
queryset = Payment.objects.filter(Landlord_FK__User_id=userid)
but this doesn't...
class PaymentsReportView(ListView):
template_name = 'payments/Payment_list.html'
userid = User.username # where the username is James
queryset = Payment.objects.filter(Landlord_FK__User_id=userid)
How can I check the output of User.username to see if it's valid? What am I missing to get the data? The code doaen't break. It just returns empty.

You can't do that at class level. What you need to do is to define a get_queryset method and do the filtering there:
class PaymentsReportView(ListView):
template_name = 'payments/Payment_list.html'
def get_queryset(self):
userid = self.request.user.username
return Payment.objects.filter(Landlord_FK__User_id=userid)
Although I must note that this implementation is odd; why is the userid the username, rather than the ID? Usually I would expect the filter to be (Landlord_FK=request.user). You should show your models.

Related

How to auto-populate database field using data from other fields in the same model

I have a model called Coverletter with 4 fields: company, role, job_posting, content.
I am trying to use the data from the first 3 fields to populate data in the 4th field.
Right now, the user inputs values for 3 fields in a form: (company, role, job_posting) using a class based view CreateView.
class CoverletterCreateView(LoginRequiredMixin, CreateView):
model = Coverletter
fields = ['company', 'role', 'job_posting']
template_name = 'coverletter/coverletter_create_form.html'
def form_valid(self, form):
form.instance.owner = self.request.user
return super().form_valid(form)
def get_success_url(self):
return reverse('coverletter:coverletter-create-content',
kwargs={'pk': self.object.pk,}
)
The user is then redirected to another class based view UpdateView via get_success_url, where the first three fields are showing with populated values.
class CoverletterCreateContentView(LoginRequiredMixin, UpdateView):
model = Coverletter
fields = ['company', 'role', 'job_posting', 'content']
template_name = 'coverletter/coverletter_create_content_form.html'
Right now the 4th field (content) is blank, but I am trying to populate the content field when the user submits the data from the first CreateView.
The data is an html string that would look something like this:
<p>Dear {{ company }} I am excited to be applying for the {{ role }} role.</p>
I am very new to Django and web development, and am struggling to understand how to do this. I am unsure where in the app to put this logic. Any guidance is appreciated!
First off, get intimate with ccbv.
Second, you're using a UpdateView, which - as you can determine above - implements, among others:
get_initial()
get_object()
Inside, get_initial(), you can get the model instance you're trying to update using get_object(). Once you have the instance, you can compose your string. Then add it to the initial data.
Result:
class CoverletterCreateContentView(LoginRequiredMixin, UpdateView):
... # fields
def get_initial(self):
if not hasattr(self, 'object'):
self.object = self.get_object(self.get_queryset())
initial = super().get_initial()
opening_sentence = (
f"Dear {self.object.company} I am excited to"
f" be applying for the {self.object.role} role."
)
initial['content'] = opening_sentence # initial[field_name] (dict)
return initial

I want to pass a parameter isloggedin user to the django frontend

I am passing a list of user objects to the frontend. The frontend wants to display currently logged in users' information seperately and other users info seperately.For that I want to pass one extra field in the users serializer. I am using viewsets and serializers to pass a list of users to the django frontend.How do i do it.
My serializer looks like
class SomeUserSerializer(serializers.ModelSerializer):
"""
Serializer for `some_user` table
"""
isLogedInUser = serializers.SerializerMethodField('is_logged_in_user')
user = UserSerializer(many=False)
def is_logged_in_user(self, request):
return self.user==request.user
class Meta:
model = SomeUser
fields = ('user', 'something', 'isLogedInUser')
Something is wrong with my is_logged_in_user method. It should be returning true or false flag along with the user object depending on whether or not it is a curently logged in user
The serializer method used by isLogedInUser is taking an argument called request. However, according to the documentation, the method is called with the object being serialized, an instance of SomeUser.
You need to change the argument and get the request via additional context, like this:
class SomeUserSerializer(serializers.ModelSerializer):
"""
Serializer for `some_user` table
"""
isLogedInUser = serializers.SerializerMethodField('is_logged_in_user', context={'request': request})
user = UserSerializer(many=False)
def is_logged_in_user(self, obj):
return obj.user == self.context['request'].user
class Meta:
model = SomeUser
fields = ('user', 'something', 'isLogedInUser')

Customize queryset in django-filter ModelChoiceFilter (select) and ModelMultipleChoiceFilter (multi-select) menus based on request

I'm using django-filter in 2 places: My Django Rest Framework API, and in my FilterViews (Django Filter's Generic ListViews.) In the case of my FilterViews I'm showing both select boxes (ModelChoiceFilter) and multi-select boxes (ModelMultipleChoiceFilter) to be filtered on.
I need to be able to limit what's in those select and multi-select inputs based on a field inside the request.
It's relatively simple to change what's listed as a kwarg in the relevant field in the FilterSet. For example, here's my FilterSet where the queryset is set as a kwarg:
class FieldFilter(django_filters.FilterSet):
"""Filter for the field list in the API"""
dataset = ModelChoiceFilter(queryset=Dataset.objects.all())
class Meta(object):
"""Meta options for the filter"""
model = Field
fields = ['dataset']
And it's relatively straightforward to limit what the result is in DRF inside the get_queryset() method. For example, here's my DRF ViewSet:
class FieldViewSet(viewsets.ReadOnlyModelViewSet):
"""A ViewSet for viewing dataset fields"""
queryset = Field.objects.all()
serializer_class = FieldSerializer
filter_class = FieldFilter
def get_queryset(self):
"""Get the queryset"""
queryset = super(FieldViewSet, self).get_queryset()
queryset = queryset.filter(
dataset__organization=self.request.organization)
return queryset
I just can't find anywhere to edit the Dataset field in the filter_class when the view is being displayed.
This is super straightforward in Django FormView generic views, but it doesn't appear that FieldViewSet follows the same get_form() structure as generic views. It's also relatively straightforward to do in the admin, but DRF/Django-Filter don't seem to follow that structure either.
Is there any way to customize the queryset in those inputs on a per-request basis? Preferably both on FilterViews and in the HTML API browser, but just in FilterViews would be fine if it's too complicated for the HTML API browser.
After hours of search, I found the solution in the official documentation here!
The queryset argument for ModelChoiceFilter and ModelMultipleChoiceFilter supports callable behavior. If a callable is passed, it will be invoked with the request as its only argument.
import django_filters as filters
from django.utils.translation import gettext as _
def ourBranches(request):
if request is None:
return Branch.objects.none()
company = request.user.profile.company
return Branch.objects.filter(company=company)
class UnitFilter(filters.FilterSet):
branch = filters.ModelChoiceFilter(
queryset=ourBranches, empty_label=_("All Branches"))
class Meta:
model = Unit
fields = ('branch', )
and in the view, I made sure to pass the request as well
qs = Unit.objects.all()
filter = UnitFilter(self.request.GET, request=self.request, queryset=qs)
table = UnitTable(filter.qs)
I also had problems finding a resolution to this.
I solved it (I think) via the following:
views.py
table_filter = ExampleFilter(request.GET, kwarg_I_want_to_pass=request.user, queryset=qs)
filters.py
class ExampleFilter(django_filters.FilterSet):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('kwarg_I_want_to_pass', None)
super(ExampleFilter, self).__init__(*args, **kwargs)
self.filters['field_to_filter'].extra.update({
'queryset': Supplier.objects.filter(related_user=self.user),
'empty_label': '',
'help_text': False
})
class Meta:
model = ExampleModel
fields = ['related_user', 'field_to_filter', ... other fields]

Need success_url to vary depending on user group in CreateView

I have two user groups, 'Owners' and 'Employees'. They can use the same form to enter data, but I want them to be directed to a different list view upon success. I have a working CreateView:
class ServiceAddBlankView(
views.LoginRequiredMixin,
views.FormValidMessageMixin,
views.SetHeadlineMixin,
generic.CreateView
):
form_class = ServiceForm
headline = 'Add Service'
form_valid_message = "Service Entered!"
model = Service
template_name = 'wesapp/service_add.html'
success_url = '/wesapp/service_list/'
But, I want to have the success_url vary by the user group.
I want the success_url to be /wesapp/service_list/ if the user group is 'Owner' and to be /wesapp/services/ if the user group is 'Employee'.
I tried this, but it is not finding any success_url at all:
owner_group = Group.objects.get(name="Owner").user_set.all()
employee_group = Group.objects.get(name="Employee").user_set.all()
class ServiceAddBlankView(
views.LoginRequiredMixin,
views.FormValidMessageMixin,
views.SetHeadlineMixin,
generic.CreateView
):
form_class = ServiceForm
headline = 'Add Service'
form_valid_message = "Service Entered!"
model = Service
template_name = 'wesapp/service_add.html'
if user in owner_group:
success_url = '/wesapp/services/'
if user in employee_group:
success_url = '/wesapp/service_list/'
The error is:
name 'user' is not defined
How do I access the user?
It's not possible to access the user in the class definition as you are doing. Instead, the CreateView has a get_success_url method, which allows you to set the success view dynamically.
In the method, you can access the request with self.request, therefore you can access the logged in user with self.request.user.
class ServiceAddBlankView(generic.CreateView):
def get_success_url(self):
if self.request.user.groups.filter(name="Owner").exists():
return '/wesapp/services/'
elif self.request.user.groups.filter(name="Employee").exists():
return '/wesapp/service_list/'
else:
return '/fallback/url/'
I've changed the query to check whether the user is in the Owner or Employee group. In your original code, you were unnecessarily loading every Owner and Employee. Note that my code is behaves slightly different if the user is an Owner and an Employee - if that's important, you need to change it.
Django's request object has access to the user. Refer to request.user as documented here :
https://docs.djangoproject.com/en/1.8/ref/request-response/#django.http.HttpRequest.user

Make BooleanField required in Django Rest Framework

I've got a model with a boolean field that I'd like to deserialize with the Django rest framework and I want the serializer to complain when a field is missing in the post request. Yet, it doesn't. It silently interprets a missing boolean as False.
class UserProfile(models.Model):
"""
Message between two users
"""
user = models.OneToOneField(User, verbose_name="django authentication user", related_name='user_profile')
newsletter = models.BooleanField(null=False)
research = models.BooleanField(null=False)
The model is created with a Serialiser like this:
class UserProfileSerializer(serializers.ModelSerializer):
research = BooleanField(source='research', required=True)
newsletter = BooleanField(source='newsletter', required=True)
class Meta:
model = UserProfile
fields = ('research', 'newsletter')
In my view I'm also creating a user, so I have some manual steps:
def post(self, request, format=None):
userprofile_serializer = UserProfileSerializer(data=request.DATA)
reg_serializer = RegistrationSerializer(data=request.DATA)
phone_serializer = PhoneSerializer(data=request.DATA)
errors = {}
if userprofile_serializer.is_valid() and reg_serializer.is_valid() and phone_serializer.is_valid():
user = reg_serializer.save()
data = reg_serializer.data
user_profile = userprofile_serializer.object
user_profile.user = user
userprofile_serializer.save()
return Response(data, status=status.HTTP_201_CREATED)
errors.update(reg_serializer.errors)
# ...
return Response(errors, status=status.HTTP_400_BAD_REQUEST)
However, the following test case fails, because the rest framework doesn't complain about the missing param but instead inserts a False in from_native
def test_error_missing_flag(self):
data = {'username': "test", 'password': "123test", 'email': 'test#me.com',
'newsletter': 'true', 'uuid': self.uuid}
response = self.client.post(reverse('app_register'), data)
# should complain that 'research' is not found
self.assertTrue('research' in response.data)
If I replace my 'research' field with an Integer field that the serializer fails as expected. Any ideas?
There was an issue with Boolean fields and the required argument. Should now be fixed in master.
See this issue: https://github.com/tomchristie/django-rest-framework/issues/1004
Add
your_field = serializers.NullBooleanField(required=False)
in serializer.
That's it. It'll work :)
For anyone who has read #Tom's accepted answer from 2013 and finds that this still doesn't work, it's because this behavior is intended for HTML form inputs. Here's the original issue.
To use serializers.BooleanField with a JSON payload, convert your request.POST to a Python dict by doing request.POST.dict() and pass it to your serializer while initializing.
Create a new custom class:
from rest_framework import serializers
class RequirableBooleanField(serializers.BooleanField):
default_empty_html = serializers.empty
Now, you can use:
research = RequirableBooleanField(required=True)
or
research = RequirableBooleanField(required=False)