I'm trying to obtain a user instance for the profile page in django app but I'm finding some difficulties implementing that functionality. I have the following blocks of code:
models.py
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, primary_key=True, on_delete=models.CASCADE, default="")
image = models.ImageField(upload_to="images/user_profile_pics/", default="images/default_profile_pics/default.jpg")
firstname = models.CharField(max_length=50)
lastname = models.CharField(max_length=50)
def __str__(self):
return f'{self.lastname} profile'
serializers.py
class user_profile_serializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = '__all__'
views.py
class user_profile(generics.GenericAPIView):
serializer_class = user_profile_serializer
def get(self, request, *args, **kwargs):
user = self.get_serializer(request.user).data
if request.user.is_authenticated:
return Response(user, status=status.HTTP_200_OK)
else:
pass
urls.py
urlpatterns = [
path('profile/', user_profile.as_view(), name="user-profile"),
]
When ever I assess the profile url, I get an error message 'AnonymousUser' object has no attribute 'data' I have tried a couple of approaches but none worked. Please, how do I obtain a specific user from the database?
request.user is AnonymousUser when the user is not logged in. In that case that object does not have data attribute. Hence the error you get. One thing you can do is check request.user.is_authenticated and if the user is not authenticated, return some other value / or None. And try logging in before trying to access the user.data value.
Related
I am doing an online classroom project in Django where I created a model named create_course which is accessible by teachers. Now I am trying to design this as the teacher who creates a class only he can see this after login another teacher shouldn't see his classes and how to add students into that particular class I created
the course model
class course(models.Model):
course_name = models.CharField(max_length=200)
course_id = models.CharField(max_length=10)
course_sec = models.IntegerField()
classroom_id = models.CharField(max_length=50,unique=True)
views.py
def teacher_view(request, *args, **kwargs):
form = add_course(request.POST or None)
context = {}
if form.is_valid():
form.save()
return HttpResponse("Class Created Sucessfully")
context['add_courses'] = form
return render(request, 'teacherview.html', context)
forms.py
from django import forms
from .models import course
class add_course(forms.ModelForm):
class Meta:
model = course
fields = ('course_name', 'course_id', 'course_sec', 'classroom_id')
Add one more field in course model that establish relationship with User model. Hence you can get the details about the teacher who has created course.
from django.contrib.auth.models import User
class course(models.Model):
course_name = models.CharField(max_length=200)
course_id = models.CharField(max_length=10)
course_sec = models.IntegerField()
classroom_id = models.CharField(max_length=50,unique=True)
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
In your view function, you can check whether logged in user is same as the created of the requested course.
def teacher_view(request, *args, **kwargs):
# since this is course specific view, you will be passing an identiier or pk of the course as an argument to this function.
course_obj = Course.objects.get(id="identifier")
if request.user == course_obj.created_by:
# logged in user is same as the creator of the course
else:
# redirect
I would prefer creating permissions and having those in specific models. You can give it a try with that too. Let me know, if it doesn't work.
In my django admin project i have to save and then display data for different user, i would that when i save automatically field user take the loged in user value and when i re logged in i can see only the data saved for my user only.
I have this kind of models.py:
class TheLinks(models.Model):
lk_name = models.CharField(max_length=20)
def __str__(self):
return self.lk_name
class UserComLinks(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="User")
l_id = models.ForeignKey(TheLinks, on_delete=models.CASCADE, verbose_name="Portal")
l_link = models.CharField(max_length=100)
def __str__(self):
return str(self.l_id)
now if i run my django admin i see this form:
well, first i would to hide the username field and make my model save in automatic this data using the current logged in user then i would that when the user logged in can see only hos data.
I try to manage admin.py in this kind of fashion:
admin.py
class UserComLinksAdmin(admin.ModelAdmin):
list_display = ('l_id', 'l_link')
def changeform_view(self, request, obj_id, form_url, extra_context=None):
try:
l_mod = UserComLink.objects.latest('id')
except Exception:
l_mod = None
extra_context = {
'lmod': l_mod,
}
return super(UserComLinksAdmin, self).changeform_view(request, obj_id, form_url, extra_context=extra_context)
but nothing change.
Can someone pleas help me about?
So many thanks in advance
You can exclude the user field from the admin form and set the value of current user before saving:
class UserComLinksAdmin(admin.ModelAdmin):
list_display = ('l_id', 'l_link')
exclude = ('user',)
def save_form(self, request, form, change):
obj = super().save_form(request, form, change)
if not change:
obj.user = request.user
return obj
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
name = models.CharField(max_length=40, blank=True)
bio = models.TextField(max_length=500, null=True, blank=True)
def get_absolute_url(self):
return reverse('userprofile:to_profile', args=[str(self.user.username)])
So I have made this model to save it as whatever.com/userprofile:to_profile/thisisusername
And on url, I have
path('accounts/profile/<username>/', ProfileDetailView.as_view(), name="to_profile"),
For the view, I have
class ProfileDetailView(DetailView):
model = Profile
template_name = "account/profile.html"
I do know that default DetailView takes pk and slug but whenever I try to pass the username with
pk_url_kwarg = "username"
I get an error
invalid literal for int() with base 10
Is there anyway we can use username for generic detailview? or is pk the only way to go?
Two things you will need to do:
First change your URL's to:
path('accounts/profile/<str:slug>/', ProfileDetailView.as_view(), name="to_profile"),
Second define the method to get the SlugField
class ProfileDetailView(DetailView):
model = Profile
template_name = "account/profile.html"
def get_slug_field(self):
"""Get the name of a slug field to be used to look up by slug."""
return 'user__username'
You can’t use pk_url_kwarg because username is not the primary key of the Profile model that you are displaying in the view.
Override get_object instead.
from django.shortcuts import get_object_or_404
def get_object(self):
return get_object_or_404(Profile, user__username=self.kwargs['username'])
I'm trying to implement a user profile in django rest framework.
Users should be able to request the profile of other users; however, since profiles contain sensitive information, I want to limit the information returned to non-owners and non-authenticated users when they request a profile.
I'm looking for a test that I can run inside my view methods that will determine which serializer to use for that request.
How can I do this?
# models.py
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='profile')
bio = models.CharField(max_length=100)
# dob is sensitive and should be protected...
dob = models.DateTimeField(blank=True, null=True)
My serializers would look like this:
# serializers.py
# Only for the owner...
class ProfileOwnerSerializer(serializers.HyperlinkedModelSerializer):
user = serializers.ReadOnlyField(source='user.id')
first_name = serializers.ReadOnlyField(source='user.first_name')
last_name = serializers.ReadOnlyField(source='user.last_name')
class Meta:
model = Profile
fields = (
'url',
'id',
'dob', #sensitive
'user',
'first_name',
'last_name', #sensitive
)
#For logged in users...
class ProfileSerializer(serializers.HyperlinkedModelSerializer):
user = serializers.ReadOnlyField(source='user.id')
first_name = serializers.ReadOnlyField(source='user.first_name')
class Meta:
model = Profile
fields = (
'url',
'id',
'bio',
'user',
'first_name',
)
#For everyone else...
class NonAuthProfileSerializer:
...
And I would try to distinguish between them here...
# views.py
class ProfileDetail(APIView):
"""
Retrieve a profile instance.
"""
# Can't user permission_classes bc I want to cater to different classes...
def get_object(self, pk):
try:
return Profile.objects.get(pk=pk)
except Profile.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
profile = self.get_object(pk)
# is_owner = ???
# is_authenticated = ???
# Define the serializer to be ProfileSerializer, ProfileOwnerSerializer, etc.
serializer = CorrectSerializer(
profile,
context={"request": request},
)
return Response(serializer.data)
I don't think it'd be too hard to check if the request was sent by the owner, since I can just cross-reference the profile id.
However, how would I check whether the user was logged in or not? I've tried looking at request.user.auth in the view method, but that seems to be None whether or not the request is logged in.
I think you should be checking with request.user.is_authenticated(). To fill in the blanks:
is_owner = profile.user == request.user
is_authenticated = request.user.is_authenticated()
I want to expand my User Model with a UserProfile model. This UserProfile model includes a ForeignKey Field. In the form, I would like to use a ModelChoiceField to pre-populate this form field.
Whenever I submit the form, I get
ValueError at /accounts/register/
Cannot assign "'13'": "UserProfile.course" must be a "Course" instance.
Any help would be appreciated!
My Code:
models.py
class Course(models.Model):
course_accid = models.CharField(max_length=10)
def __str__(self):
return self.course_accid
class UserProfile(models.Model):
# This line is required. Links UserProfile to a User model instance.
user = models.OneToOneField(User)
website = models.URLField(blank=True)
picture = models.ImageField(upload_to='profile_images', blank=True)
course = models.ForeignKey(Course)
def __unicode__(self):
return self.user.username
def user_registered_callback(sender, user, request, **kwargs):
profile = UserProfile(user = user)
profile.website = request.POST["website"]
profile.course = Course.objects.get(pk=request.POST["course"]),
profile.save()
forms.py
class RegistrationForm(RegistrationForm):
course = forms.ModelChoiceField(queryset=Course.objects.all())
website = forms.URLField()
So, the problem that's occurring is that course needs to be set to a course instance with a step before, on forms.py, before it's a ModelChoiceField. The reason why is because querying it, like you're doing with queryset is really just searching for a string that matches, not the actual object.
If you break it up into two steps,
class = [some_method_for_getting_a_class_object]
UserProfile.class = class
Then it should get rid of that error.