Django Rest Framework slug_field error - python

I have this serializer and model. I want to show in my API the field username of User model, but I receive this error.
AttributeError at /api/v1/client_share_requests/1/
'Profile' object has no attribute 'username'
serializers.py
class ClientShareRequestSerializer(serializers.ModelSerializer):
checked_by = serializers.SlugRelatedField(
many=True,
queryset=Profile.objects.all(),
slug_field='username'
)
class Meta:
model = ClientShareRequest
fields = ('checked_by')
models.py
class Profile(models.Model):
user = models.OneToOneField(User, related_name='profile')
class ClientShareRequest(models.Model):
checked_by = models.ManyToManyField(Profile, blank=True,
related_name='checked_by')
I try to access the User model instance like this:
checked_by = serializers.SlugRelatedField(
many=True,
queryset=Profile.objects.all(),
slug_field='user.username'
)
but I receive this error:
'Profile' object has no attribute 'user.username'
Thanks for helping. (Sorry for my English :P)

My guess is DRF does not allow nested attribute lookups on SlugRelatedFields. Simple workaround would be to add a username property on the Profile model and use this in the serializer:
class Profile(models.Model):
user = models.OneToOneField(User, related_name='profile')
#property
def username(self):
return self.user.username
class ClientShareRequest(models.Model):
checked_by = models.ManyToManyField(Profile, blank=True,
related_name='checked_by')
class ClientShareRequestSerializer(serializers.ModelSerializer):
checked_by = serializers.SlugRelatedField(
many=True,
read_only=True,
slug_field='username'
)
class Meta:
model = ClientShareRequest
fields = ('checked_by', )
This works for reads :)

Related

tried to connect a ModelForm

i am reciving a "value error"
because of "ModelForm has no model class specified."
i tried to check the : models.py forms.py and views.py but all looks pretty good for me
views.py :
class CreatePostView(LoginRequiredMixin,CreateView):
login_url='/login/'
redirect_field_name='Myblog/post_detail.html'
form_class = PostForm
model = Post
models.py:
class Post(models.Model):
author = models.ForeignKey('auth.User',on_delete=models.CASCADE)
title = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True,null=True)
forms.py:
class PostForm(ModelForm):
class meta:
model = Post
fields = ('author','title','text')
from app.urls.py
url(r'^post/new/$',views.CreatePostView.as_view(),name='post_new'),
Meta is with an uppercase, according to PEP-8 the names of classes all start with an uppercase. In your form, you should write:
# app/forms.py
class PostForm(ModelForm):
class Meta:
model = Post
fields = ('author','title','text')
Since you wrote it as meta, Django indeed did not understand what model you were using.
If you however do not write a form with specific items, you can - like #DanielRoseman says, just define this at the CreateView [Django-doc]:
class CreatePostView(LoginRequiredMixin,CreateView):
login_url='/login/'
redirect_field_name='Myblog/post_detail.html'
model = Post
fields = ('author', 'title', 'text')
Django can construct a form class through the modelform_factory [Django-doc].

DRF Serializer Relations / JSON API Framework

*Update 1: Attempts with corresponding errors now shown in serializer code
*Update 2: I've narrowed the issue to a conflict with the JSON Api framework I'm using
I'm fairly new to Python and Django and I'm struggling quite a bit with relations. I'm able to create the relations in the database however I've been unable to serialize the models together for a response object, despite trying every method in the documentation which seems very straightforward. My goal is to return both models from an APIView on login and if this code doesn't error I get a response with just the user model. The errors vary based on the different techniques and are similar to what other users get when having trouble with relations, however their fixes haven't solved my problem.
I'm wondering if there's something obvious I'm not doing right. I'm happy to share more code but I'm really at a loss as to how to proceed.
Fyi: My models are in different apps which is why the fk reference is users.User
Models:
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=50, unique=True)
password = models.CharField(max_length=100)
name = models.CharField(max_length=50)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
has_business = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['password']
def get_full_name(self):
return self.name
def get_short_name(self):
return self.name
def __str__(self):
return self.email
class Business(models.Model):
name = models.CharField(max_length=50, unique=True)
address = models.CharField(max_length=100)
phone = models.CharField(max_length=20)
description = models.CharField(max_length=500)
user = models.ForeignKey(
'users.User',
related_name='business',
unique=False,
on_delete=models.CASCADE
)
has_driver = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
created = models.DateTimeField(auto_now_add=True)
Serializer:
class UserSerializer(serializers.ModelSerializer):
token = srs.SerializerMethodField()
biz = BusinessSerializer(many=True, read_only=True,
source='business.id')
error: just returns user model
biz = BusinessSerializer(read_only=True, many=True, source='business')
error: ForeignKey' object has no attribute
biz = serializers.RelatedField(many=True, read_only=True)
error: 'User' object has no attribute 'biz'
biz = serializers.ReadOnlyField(source='businesses.id')
error: RelatedManager object at 0x7fed496fe208> is not JSON
serializable
biz = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
error:'User' object has no attribute 'biz'
class Meta:
model = models.User
fields = ('id', 'email', 'password', 'name', 'token', 'has_business', 'biz')
extra_kwargs = {'password': {'write_only': True}}
def create(self, validated_data):
user = models.User(
email = validated_data['email'],
name = validated_data['name'],
phone = validated_data['phone'],
location = validated_data['location'],
)
user.set_password(validated_data['password'])
user.save()
return user
View:
class LoginUser(APIView):
permission_classes = (permissions.AllowAny,)
resource_name = 'users'
def post(self, request):
email = request.POST.get('email', False)
password = request.POST.get('password', False)
if(email and password):
lu = UserAuth()
authenticated_user = lu.auth(email=email, password=password)
if authenticated_user is not None:
if authenticated_user.is_active:
serializer = serializers.UserSerializer(authenticated_user, context={'request': request})
return Response(serializer.data, status=status.HTTP_200_OK)
You have to use the related_name in your serializer.
You can take a look here
In this example you can see that the Track Model (analog to your Business Model) has the field called album with related_name='tracks'
Then in the AlbumSerializer (the analog to your User Model):
class AlbumSerializer(serializers.ModelSerializer):
tracks = serializers.StringRelatedField(many=True)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
So, in summary you have to use your related_name business
This is the example with a StringRelatedField, but you can of course return the complete object using this
Turns out I was using a beta version (pip install djangorestframework-jsonapi==2.0.0-beta.1) of the JSON API Framework and it wasn't handling relations very well. I picked the beta because it was the one the documentation lists which is kind of odd. You have to dig a bit for the more stable versions. I'm embarrassed to say how long that took me to figure out.
Here's the stable version as of this day: pip install djangorestframework-jsonapi==2.2.0

Method in model that filter by user

My model:
class Document(models.Model):
title = models.CharField(_('title'), null=False, blank=False, max_length=250)
description = models.TextField(_('description'), null=True, blank=True)
is_favourite = my_method()
class FavouriteDocumentUser(models.Model):
document = models.ForeignKey(Document)
user = models.ForeignKey(CustomUser)
class Meta:
unique_together = ('document', 'user',)
I need a field 'is_favourite' that is true if exist in FavouriteDocumentUser a row with the id of the document and the id of logged user.
So the problem is: how can I get the current user in a method of the model?
I'm using these models into django rest framework.
You can't, because Django ORM is not aware of Django authentication. The current user is available in the request object, which is only available to your views. You need to pass your request.user to your model method. For example:
class Document(models.Model):
...
def is_favourite(user):
return self.favoritedocumentuser_set().filter(user=user).exists()
then you call this method from your views:
def my_view(request):
...
if mydocument.is_favorite(request.user):
...do something...

Django REST Framework: change field names

My Django application provides readonly api access to the users of the site. I created a user profile model and use it in the serializer of the user model:
Model:
# + standard User Model
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
display_name = models.CharField(max_length=20, blank=True)
Serializer:
class UserProfileSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = UserProfile
fields = ('display_name',)
class UserSerializer(serializers.HyperlinkedModelSerializer):
userprofile_set = UserProfileSerializer(many=False, label='userprofile')
class Meta:
model = User
fields = ('id', 'username', 'userprofile_set')
This works but the field userprofile_set looks ugly. Is it possible to change the field name?
To complement your answer, you can also make use of relationships' related names:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True, related_name='profiles')
display_name = models.CharField(max_length=20, blank=True)
that way you can also use this in your code:
user = User.objects.last() #some user
user.profiles.all() #UserProfiles related to this user, in a queryset
user.profiles.last() #the last UserProfile instance related to this user.
May I recommend that you turn that ForeignKey into a OneToOneField? that way an user can have one and just one user profile, and you don't need to establish uniqueness:
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile')
display_name = models.CharField(max_length=20, blank=True)
Oh, I can name the variable userprofile_set as I like. First I tested the name userprofile which conflicted. If I name the field profile it works. :)
class UserSerializer(serializers.HyperlinkedModelSerializer):
profile = UserProfileSerializer(many=False, label='userprofile')
class Meta:
model = User
fields = ('id', 'username', 'profile')

Django rest framework auto-populate filed with user.id

I cant find a way to auto-populate the field owner of my model.I am using the DRF .If i use ForeignKey the user can choose the owner from a drop down box , but there is no point in that.PLZ HELP i cant make it work.The views.py is not include cause i think there is nothing to do with it.
models.py
class Note(models.Model):
title = models.CharField(max_length=200)
body = models.TextField()
cr_date = models.DateTimeField(auto_now_add=True)
owner = models.CharField(max_length=100)
# also tried:
# owner = models.ForeignKey(User, related_name='entries')
class Meta:
ordering = ('-cr_date',)
def __unicode__(self):
return self.title
serializers.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', "username", 'first_name', 'last_name', )
class NoteSerializer(serializers.ModelSerializer):
owner = request.user.id <--- wrong , but is what a need.
# also tried :
# owner = UserSerializer(required=True)
class Meta:
model = Note
fields = ('title', 'body' )
Django Rest Framework provides a pre_save() method (in generic views & mixins) which you can override.
class NoteSerializer(serializers.ModelSerializer):
owner = serializers.Field(source='owner.username') # Make sure owner is associated with the User model in your models.py
Then something like this in your view class:
def pre_save(self, obj):
obj.owner = self.request.user
REFERENCES
http://www.django-rest-framework.org/tutorial/4-authentication-and-permissions#associating-snippets-with-users
https://github.com/tomchristie/django-rest-framework/issues/409#issuecomment-10428031

Categories