I am trying to access the username attribute of a Django User object from a Profile object that is related by a OneToOneField.
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
username = models.TextField(default=user.username, primary_key=True)
image = models.ImageField(upload_to='images/profile')
header = models.CharField(max_length=64)
slug = AutoSlugField(populate_from='x')
bio = models.CharField(max_length=300, blank=True)
The intent of this is to be able to get a Profile object using a ReactJS frontend by passing the username provided at login back to a profile detail endpoint in a Django API, where the username is the primary key for the endpoint.
path('<pk>/profile/', ShowProfilePageView.as_view(), name='show_profile_page'),
I've tried many different things for the default argument passed to the Profile username attribute, but nothing is working so far. Is this even possible?
Addendum 1: ShowProfilePageView view
class ShowProfilePageView(generics.RetrieveUpdateDestroyAPIView):
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
model = Profile
I think you can simply override the lookup_field in the View, like this:
class ShowProfilePageView(generics.RetrieveUpdateDestroyAPIView):
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
model = Profile
lookup_field='user__username'
lookup_url_kwarg='username'
And update the url like this:
path('<str:username>/profile/', ShowProfilePageView.as_view(), name='show_profile_page')
Because through lookup_field, the view will look for the value in User model from Profile model. And lookup_url_kwargs is to map what value it should use from urls. More information can be found in documentation. FYI you should remove username field from Profile model, it should use AutoField(which is the default field for primary key in models).
To access the attribute of one-to-one field you can just do this:
profile = Profile.objects.get(pk='profile_pk') # an object of profile
username = profile.user.username
To search Profile via username:
profile = Profile.objects.get(user=User.objects.get(username='username'))
Thus, you don't need to define username field on Profile class
Related
I am building a blog website and I am using Django rest framework
I want to fetch top 2 comments for a particular post along with their related data such as user details.
Now I have user details in two models
User
People
and the comments model is related to the user model using foreign key relationship
Models ->
Comments
class Comment(models.Model):
comment = models.TextField(null=True)
Created_date = models.DateTimeField(auto_now_add=True)
Updated_date = models.DateTimeField(auto_now=True)
post = models.ForeignKey(Post, on_delete=models.CASCADE,
related_name='comments_post')
user = models.ForeignKey(User, on_delete=models.CASCADE,
related_name='comments_user')
The People model is also connected to the user model with a foreign key relationship
People Model ->
class People(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,related_name='people')
Name = models.CharField(max_length=255,null=True)
following = models.ManyToManyField(to=User, related_name='following', blank=True)
photo = models.ImageField(upload_to='profile_pics', blank=True,null=True)
Phone_number = models.CharField(max_length=255,null=True,blank=True)
Birth_Date = models.DateField(null=True,blank=True)
Created_date = models.DateTimeField(auto_now_add=True)
Updated_date = models.DateTimeField(auto_now=True)
for fetching the comments I am using rest-framework and the serializers look like this
class UserSerializer(serializers.Serializer):
username = serializers.CharField(max_length=255)
class peopleSerializer(serializers.Serializer):
Name = serializers.CharField(max_length=255)
class commentsSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
comment = serializers.CharField(max_length=255)
Created_date = serializers.DateTimeField()
user = UserSerializer()
people = peopleSerializer()
The query to fetch the comments look like this ->
post_id = request.GET.get('post_id')
comments = Comment.objects.filter(post_id=post_id).select_related('user').prefetch_related('user__people').order_by('-Created_date')[:2]
serializer = commentsSerializer(comments, many=True)
return Response(serializer.data)
I am getting this error ->
Got AttributeError when attempting to get a value for field `people` on serializer `commentsSerializer`. The serializer field might be named incorrectly and not match any attribute or key on the `Comment` instance. Original exception text was: 'Comment' object has no attribute 'people'.
Unable to find a way out.
The source is user.people, not people, so:
class commentsSerializer(serializers.Serializer):
# …
people = peopleSerializer(source='user.people')
In the .select_related(…) [Django-doc] to can specify user__people: this will imply selecting user and will fetch the data in the same query, not in an extra query as is the case for .prefetch_related(…) [Django-doc]:
post_id = request.GET.get('post_id')
comments = Comment.objects.filter(
post_id=post_id
).select_related('user__people').order_by('-Created_date')[:2]
serializer = commentsSerializer(comments, many=True)
return Response(serializer.data)
Note: normally a Django model is given a singular name, so Person instead of People.
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
Note: normally the name of the fields in a Django model are written in snake_case, not PascalCase, so it should be: created_date instead of Created_date.
I have some model like below in my blog-like website, I hope different user can query their own data. SO, I need save user id in my model.
However, modeladmin of wagtail only has get_queryset() but no save_model()
class Info(Orderable):
user = models.ForeignKey('auth.User',
on_delete=models.CASCADE,
blank=False, null=True,
related_name='+',)
Is there any way to store user id in wagtail admin panel?
The other way is pre-populate it, I try to do this and it's work well.
def create_view(self, request):
view = super().create_view(request)
self._set_username(view, request)
return view
def _set_username(self, view, request):
if hasattr(view, 'context_data'):
form = view.context_data['form']
form.fields['name'].widget.attrs['value'] = request.user
if you mean (from) admin, yes you can, but if you mean to admin panel from the model class, no you can't, handling the request is job of Views(the controllers) once the URL been requested, the view evaluate many things, one of them is request.user, and this one is an object of User model, you can then ask for id by (requested.user.id).. but of course in the views.py, or wagtail_hooks.py
Here is how my model looks like:
class Maintab(models.Model):
email = models.CharField(max_length=255)
username = models.CharField(max_length=255)
password = models.CharField(max_length=255)
lab_name = models.CharField(max_length=255)
type = models.CharField(max_length=255)
def __str__(self):
return self.username
I want to append the User table that looks after the login, with the username and password of my Maintab model. If only the username and password of the user table could get updated.
Or if I could use Maintab as my Custom UserModel (but it would not have attributes like is_active, is_staff, etc)
Seems like creating your own user models by subclassing the existing user model is the right solution as it enables you to use the existing django code while also adding your own user attributes.
Here is a link to the Django documentation where they describe how to do this:
https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#using-a-custom-user-model-when-starting-a-project
I'm django learner and I'm trying to design multiple userprofile system.
I recently saw the create_profile function for single userProfile. How can I redesign it to multi user profile creation function?
def create_profile(sender,**kwargs):
if kwargs["created"]:
user_profile=Student.objects.create(user=kwargs["instance"])
post_save.connect(create_profile,sender=User)
Have two models for each profile type. If you want, have them inherit from a base model but you don't need to.
class Student(models.Model):
user = models.ForeignKey(User)
# more fields
class Master(models.Model):
user = models.ForeignKey(User)
# more fields
myuser = User.objects.get(...)
student = Student.objects.create(user=myuser)
master = Master.objects.create(user=myuse
I have Guest model in my app:
class Guest(models.Model):
event = models.ForeignKey(Event, related_name='guests')
contact = models.ForeignKey(Contact, related_name='guests')
attending_status = models.CharField(max_length=32, choices=ATTENDING_CHOICES, default='no_rsvp')
number_of_guests = models.SmallIntegerField(default=0)
comment = models.CharField(max_length=255, blank=True, default='')
updated = models.DateTimeField(blank=True, null=True)
Event and Contact I fill up by myself in Admin when creating a guest. On the site all I want is a guest to fill up the form where he refreshes his attending status, points out number of guests and leaves a comment.
class RSVPForm(forms.Form):
attending = forms.ChoiceField(choices=VISIBLE_ATTENDING_CHOICES, initial='yes', widget=forms.RadioSelect)
number_of_guests = forms.IntegerField(initial=0)
comment = forms.CharField(max_length=255, required=False, widget=forms.Textarea)
How can I save the changes to the Guest model instance? How can I access the guest's id when saving the changes to his profile?
You are probably looking for Django's ModelForms. Instead of subclassing forms.Form in your RSVPForm class, you should subclass forms.ModelForm. Then you can use the features of the model form class to help you achieve what you want (hide some fields, etc). An example is below:
class RSVPForm(forms.ModelForm):
class Meta:
model = Guest
fields = ('attending_status', 'number_of_guests', 'comment')
This will do essentially what you want, but you will need to remember to provide an instance keyword argument to the form constructor in your view function. This argument is the instance of the Guest model you will be updating with the form.
form = RSVPForm(instance=guest_object)
Now calls to the form.save() method will automatically save the new data to this Guest object instance. You just need to make sure that you always pass the instance keyword argument, even when using request.POST:
form = RSVPForm(request.POST, instance=guest_object)