RelatedManager' object has no attribute 'description - python

I perform request http://167.71.57.114/api2/workout-exercises/3
I want to receive data about WorkoutExercise object number 3 (detail view)
Got AttributeError when attempting to get a value for field description on serializer ExerciseSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the RelatedManager instance.
Original exception text was: 'RelatedManager' object has no attribute 'description'.
serializers.py
class WorkoutExerciseSerializer(serializers.ModelSerializer):
exercises = ExerciseSerializer()
class Meta:
model = WorkoutExercise
fields = ('week', 'exercises')
views.py
class WorkoutExerciseViewSet(viewsets.ModelViewSet):
queryset = WorkoutExercise.objects.all()
serializer_class = WorkoutExerciseSerializer
http_method_names = ['get', 'post']
models.py
class WorkoutExercise(models.Model):
workout_program = models.ForeignKey(WorkoutProgram, on_delete=models.CASCADE, related_name='workout_exercises')
week = models.PositiveIntegerField(default=1)
day = models.PositiveIntegerField(default=1)
order = models.PositiveIntegerField(default=1)
def save(self, *args, **kwargs):
if not self.pk:
last_order = WorkoutExercise.objects.all().aggregate(largest=models.Max('order'))['largest']
if last_order is not None:
self.order = last_order + 1
return super(WorkoutExercise, self).save(*args, **kwargs)
def get_workout_programs(self):
return self.workout_program.name
def get_exercises(self):
pass
def __str__(self):
return self.workout_program.name
class Meta:
ordering = ('week', 'day')

Based on the fact that exercises is plural, and RelatedManager error, it means that there are multiple Exercises, so you need to serialize these with a many=True parameter:
class WorkoutExerciseSerializer(serializers.ModelSerializer):
exercises = ExerciseSerializer(many=True)
class Meta:
model = WorkoutExercise
fields = ('week', 'exercises')

Related

Update many objects in one query DRF

I need to bulk update ("is_read" = True) Message instanses by given list of ids in one request with this code:
{"ids": [11, 4, 7]}
Model:
class Message(models.Model):
text = models.TextField(max_length=500, verbose_name=_("Text"))
sender = models.ForeignKey(
to=User,
on_delete=models.CASCADE,
related_name="sender_message",
verbose_name=_("User"),
)
thread = models.ForeignKey(
to="Thread",
on_delete=models.CASCADE,
related_name="thread_message",
verbose_name=_("Thread"),
)
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Created"))
updated_at = models.DateTimeField(auto_now=True, verbose_name=_("Updated"))
is_read = models.BooleanField(default=False, verbose_name=_("Is read"))
I have this serializer:
class MessageIsReadSerializer(serializers.ModelSerializer):
class Meta:
model = Message
fields = ("id", "text", "sender", "is_read")
And method in views.py:
class MessageIsRead(APIView):
permission_classes = (AllowAny,)
queryset = Message.objects.all()
def put(self, request, *args, **kwargs):
id_list = request.data['ids']
instances = []
for item in id_list:
obj = self.queryset.filter(id=item)
obj.is_read = True
instances.append(obj)
serializer = MessageIsReadSerializer(instances, many=True)
return Response(serializer.data)
urls.py
urlpatterns = [
path("messages-read/", MessageIsRead.as_view()),
]
But as a result of running this query I get an error:
AttributeError at /messages-read/
Got AttributeError when attempting to get a value for field `text` on serializer
`MessageIsReadSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the
`QuerySet` instance.
Original exception text was: 'QuerySet' object has no attribute 'text'.
What is wrong?
With help of Bartosz Stasiak I've fixed my verion of put method.
def put(self, request, *args, **kwargs):
id_list = request.data['ids']
instances = []
for item in id_list:
obj = self.queryset.get(id=item)
obj.is_read = True
obj.save()
instances.append(obj)
serializer = MessageIsReadSerializer(instances, many=True)
return Response(serializer.data)
First: here you are getting a queryset, not an instance, so later in your code you are appending querysets to the instances list. If you want to access single instance you should use get instead of filter
single_instance = self.queryset.get(id=item)
If you want to update multiple items you can use:
def put(self, request, *args, **kwargs):
id_list = request.data['ids']
instances = self.queryset.filter(id__in=id_list)
instances.update(is_read=True)
serializer = MessageIsReadSerializer(instances, many=True)
return Response(serializer.data)

django, Changing field values ​in model before saving to database

class PlayerList(models.Model):
name = models.CharField(max_length=300)
position = models.CharField(max_length=200)
h_code = models.ForeignKey(HList, related_name="h_code", on_delete=models.CASCADE)
d_code = models.CharField(primary_key=True, max_length = 200, editable=False)
Serializers.py
class PlayerSerializer(serializers.ModelSerializer):
class Meta:
fields = ["name", "position", "h_code", "d_code"]
model = PlayerList
view.py
class PostPlayer(generics.ListCreateAPIView):
queryset = PlayerList.objects.all().order_by('-d_code')
serializer_class = PlayerListSerializer
def get(self, request, *args, **kwargs):
d_code = request.data.get('h_code') + 'test'
print(d_code)
print(d_code) :
h000001test
When entering a value through api, I want to implement that the entered value is changed to another value in view.py and saved in the db.
I want to save d_code processed by def get in db.
I don't know what to do. Can you please let me know?
There is no answer, so I will post again.
You can override your views perform_create() method, as stated in the docs (you might have to scroll a little, its in the Save and deletion hooks section:
class PostPlayer(generics.ListCreateAPIView):
queryset = PlayerList.objects.all().order_by('-d_code')
serializer_class = PlayerListSerializer
def get(self, request, *args, **kwargs):
d_code = request.data.get('h_code') + 'test'
print(d_code)
...
...
def perform_create(self, serializer):
d_code = request.data.get('h_code') + 'test'
#do something with d_code
new_code = d_code + 'someSampleValue'
serializer.save(d_code=new_code)

How to filter Django Form dropdown for currently logged-in user (Class Based Views)

I have the two models, Fillup and Car, and the Fillup model has a Foreign key (for recording times you fill up your car with gas, for example), and in the form to create a new Fillup, I want to limit the dropdown for the Car field to only Cars associated with the current user, but right now it's showing all users cars. I've seen a couple solutions that involve passing the request into the form from the view but I can't figure out how to do it using the Class Based Views I currently have set up. Here's my code:
models.py
class Fillup(models.Model):
username = models.ForeignKey(User,on_delete=models.CASCADE)
date = models.DateField(default=date.today)
price_per_gallon = models.FloatField()
trip_distance = models.FloatField()
gallons = models.FloatField()
car = models.ForeignKey('Car',on_delete=models.CASCADE)
#property
def total_sale(self):
return round(self.price_per_gallon*self.gallons, 2)
#property
def mpg(self):
return round(self.trip_distance/self.gallons, 4)
class Car(models.Model):
username = models.ForeignKey(User,on_delete=models.CASCADE)
name = models.CharField(max_length=25)
make = models.CharField(max_length=25)
model = models.CharField(max_length=25)
model_year = models.IntegerField(choices=MODEL_YEARS)
status = models.BooleanField(choices=STATUS)
def __str__(self):
return self.name
views.py
class FillupListView(ListView):
model = Fillup
context_object_name = 'fillup_list'
ordering = ['-date']
# NOT USING THIS YET
# def get_queryset(self):
# return Fillup.objects.filter(user=self.request.user)
class CarListView(ListView):
model = Car
ordering = ['name']
class NewFillup(LoginRequiredMixin,CreateView):
model = Fillup
fields = ('date', 'price_per_gallon', 'trip_distance', 'gallons', 'car')
redirect_field_name = 'fillup_list'
def form_valid(self, form):
form.instance.username = self.request.user
return super().form_valid(form)
class NewCar(LoginRequiredMixin,CreateView):
model = Car
fields = ('name', 'make', 'model', 'model_year', 'status')
redirect_field_name = 'car_list'
def form_valid(self, form):
form.instance.username = self.request.user
return super().form_valid(form)
forms.py
class FillupForm(forms.ModelForm):
def __init__(self, user, *args, **kwargs):
super(FillupForm,self).__init__(*args, **kwargs)
self.fields['car'].queryset = Car.objects.filter(username=user)
class Meta():
model = Fillup
fields = ('date', 'price_per_gallon', 'trip_distance', 'gallons', 'car')
class CarForm(forms.ModelForm):
class Meta():
model = Car
fields = ('name', 'make', 'model', 'model_year', 'status')
The overwriting of the init method in FillupForm was just one of the things I tried to get this to work, adapted from another Stackoverflow answer, but it didn't seem to have any effect. Any advice/examples to get this working would be appreciated! And let me know if I should supply any more pieces of my code
I ended up getting my answer to this from r/djangolearning on Reddit.
I needed to add the following to both of my CreateViews:
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
They also pointed out that I needed to replace the fields=('blah blah blah') on both CreateViews with form_class=forms.Fillup/Car
I hope this helps someone with the same issue as me!
You can do something like this in the init method.
cars = Car.objects.filter(username=user)
self.fields['car'].autocomplete = False
self.fields['car'].queryset = users
Hope this helps.

DRF- Error when creating a new instance in an M2M through model

I have the following two models:
class User(models.Model):
user_id = models.CharField(
max_length=129,
unique=True,
)
user_article = models.ManyToManyField(
Article,
through="UserArticle",
)
occupation = models.CharField(max_length=100, default='null')
def __str__(self):
return self.user_id
and
class Article(models.Model):
uuid = models.UUIDField(editable=False, unique=True)
company = models.ForeignKey(
Company,
on_delete=models.PROTECT,
related_name='article_company_id',
)
articleType = models.ForeignKey(
ArticleType,
on_delete=models.PROTECT,
related_name='type',
)
date_inserted = models.DateField()
def __str__(self):
return self.uuid
which are modeled with a many-to-many relationship, using this through model:
class UserArticle(models.Model):
user = models.ForeignKey(User, to_field='user_id',
on_delete=models.PROTECT,)
article = models.ForeignKey(Article, to_field='uuid',
on_delete=models.PROTECT,)
posted_as = ArrayField(
models.CharField(max_length=100, blank=True),)
post_date = models.DateField()
class Meta:
db_table = "core_user_articles"
Here's my view:
class BatchUserArticleList(mixins.ListModelMixin,
mixins.CreateModelMixin,
generics.GenericAPIView):
queryset = UserArticle.objects.all()
serializer_class = BatchUserArticleSerializer
def create(self, request, *args, **kwargs):
serializer = BatchUserArticleSerializer(data=request.data)
if not serializer.is_valid():
return response.Response({'Message': 'POST failed',
'Errors': serializer.errors},
status.HTTP_400_BAD_REQUEST)
self.perform_create(serializer) # equal to serializer.save()
return response.Response(serializer.data, status.HTTP_201_CREATED)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
The problem I'm facing is when I want to POST data, of the following format, in the M2M table:
{
"posted_as": ["news"],
"post_date": "2020-05-26",
"user": "jhtpo9jkj4WVQc0000GXk0zkkhv7u",
"article": [
"11111111",
"22222222"
]
}
The above contains a list of many articles so I used a custom field in my serializer in order to extract each article, create a new UserArticle object and insert it, using bulk_create, into my M2M table. I think that's the way to go when the incoming data do not map exactly to the DB model, but I might be wrong. So please comment if you see something off with this approach.
Here is the serializer:
class BatchUserArticleSerializer(serializers.ModelSerializer):
article= ArticleField(source='*') #custom field
class Meta:
model = UserArticle
fields = ('posted_as', 'post_date', 'user', 'article')
def validate(self, data):
post_date = data['post_date']
if post_date != date.today():
raise serializers.ValidationError(
'post_date: post_date is not valid',
)
return data
def create(self, validated_data):
post_as = list(map(lambda item: item, validated_data['posted_as']))
post_date = validated_data['post_date']
user = validated_data['user']
list_of_articles = validated_data['article']
user_object = User.objects.get(user_id=user)
articles_objects = list(map(lambda res: Article.objects.get(uuid=res), list_of_articles))
user_articles_to_insert = list(map(
lambda article: UserArticle(
posted_as=posted_as,
post_date=post_date,
article=article,
user=user_object),
articles_objects))
try:
created_user_articles = UserArticles.objects.bulk_create(user_articles_to_insert)
for res in created_user_articles:
res.save()
return created_user_articles
except Exception as error:
raise Exception('Something went wrong: {0}'.format(error))
and
class ArticleField(serializers.Field):
def to_representation(self, value):
resource_repr = [value.article]
return resource_repr
def to_internal_value(self, data):
internal_repr = {
'article': data
}
return internal_repr
This seems to work ok as I can see data being correctly inserted in the UserArticle table:
id | posted_as | post_date | user | article
1 | news | 2020-05-26 | jhtpo9jkj4WVQc0000GXk0zkkhv7u | 11111111
2 | news | 2020-05-26 | jhtpo9jkj4WVQc0000GXk0zkkhv7u | 22222222
The problem comes when code reaches this line:
response.Response(serializer.data, status.HTTP_201_CREATED)
and more specifically, the error I'm getting is:
AttributeError: Got AttributeError when attempting to get a value for field `posted_as` on serializer `BatchUserArticleSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `list` instance. Original exception text was: 'list' object has no attribute 'posted_as'.
The original exception error is raised at the instance = getattr(instance, attr) line of the def get_attribute(instance, attrs) function in the fields.py DRF source.
What am I missing here?
First of all, there is no reason to call save method for each of bulk-created instances.
Second one is reason of exception. You call create viewset method. it calling serializers create method which must return only one instance (created object). but your serializer returns list created_user_articles. List really have no field posted_as.
So, there is two ways to fix it.
First one is override create method in view, to change the way of data representation. For ex. use another serializer for response data:
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
created_user_articles = self.perform_create(serializer)
# use another way to get representation
response_data = AnotherUserArticleSerializer(created_user_articles, many=True).data
return Response(response_data, status=status.HTTP_201_CREATED, headers=headers)
def perform_create(self, serializer):
# add return to get created objects
return serializer.save()
Second one is return only one instance in create method of your serializer.

Django REST framwork mongoengine ValueError: The source SON object needs to be of type 'dict'

I'm working a project, and use Django REST framework and mongo engine, and I'm confused a question two days, and the detail see below:
class Jvv(EmbeddedDocument):
unit = fields.StringField()
unitValue = fields.IntField()
class Meta:
db_table = 'imagerecognition'
class ImageRecognition(Document):
imageUrl = fields.StringField(default='', max_length=100)
createTime = fields.DateTimeField(default=datetime.now())
ddPercent = fields.FloatField(required=False, default='')
jvv = fields.ListField(fields.EmbeddedDocumentField(Jvv))
def __str__(self):
return self.imageUrl
class Meta:
db_table = 'imagerecognition'
then the serializer.p document is :
class JvvSerializer(mongoserializers.EmbeddedDocumentSerializer):
class Meta:
model = Jvv
fields = '__all__'
class ImageUrlSerializer(mongoserializers.DocumentSerializer):
jvv = JvvSerializer(many=True)
class Meta:
model = ImageRecognition
fields = ('imageUrl', 'createTime', 'ddPercent', 'jvv')
and the views.py content is below:
class ImageUrlSave(views.APIView):
def get(self, request, *args, **kwargs):
imgs = ImageRecognition.objects(imageUrl='白菜')
serializer = ImageUrlSerializer(imgs, many=True)
ImageRecognition(imageUrl='土豆', ddPercent=8.22, jvv={'unit':'m', 'unitValue':12}).save()
data = serializer.data
return Response({
'msg': 'SUCCESS',
'code_status': 1000,
'result': data
})
the question is the mongodatabases have been completed, I want to take some data from it, but when I runserver, it shows
raise ValueError("The source SON object needs to be of type 'dict'")
ValueError: The source SON object needs to be of type 'dict', how can I handle this problem, and I am Looking forward to get answer. Thank you.

Categories