Django with Postgresql update object, prevent order re-ordering - django

in django production mode with postgreSQL, When I got an still existing object/row from the database, edit/update it and store it back, the row is moved to the end of the table.
object 1
object 2
object 3
after done editing object 1
object 2
object 3
object 1
models.py
class itemModels(models.Model):
name = models.CharField(max_length=50)
photo = models.ImageField(max_length=200, blank=True, default="default.png")
photo2 = models.ImageField(max_length=200, blank=True, default="default2.png")
price = models.DecimalField(max_digits=6, decimal_places=2)
sku = models.CharField(max_length=50, unique=True)
description = models.CharField(max_length=255)
def __self__(self):
return self.name
views.py
class itemViewSet(viewsets.ModelViewSet):
queryset = itemModels.objects.all()
serializer = itemSerializers()
renderer_classes = [TemplateHTMLRenderer]
template_name = 'product-list.html'
lookup_field = 'pk'
# list all item
def list(self, request):
queryset = itemModels.objects.all()
context = {'posts': queryset}
return Response(context)
# serializer form
def serializer_list(self, request):
serializer = itemSerializers()
return Response({'serializer': serializer}, template_name='product-create.html')
def retrieve(self, request, pk):
profile = get_object_or_404(itemModels, pk=pk)
serializer = itemSerializers(profile)
return Response({'serializer': serializer}, template_name='product-edit.html')
def update(self, request, pk):
profile = get_object_or_404(itemModels, pk=pk)
serializer = itemSerializers(profile, data=request.data)
if serializer.is_valid():
serializer.save()
print('status: status.Item Update')
return redirect('item')
else:
print('status: status.Item Bad Update')
i want to prevent this re-ordering happen, is there something i miss out ? thanks guys
Note:
if i am using development mode and switch the to django dummie database, this wont happen.

def list(self, request):
queryset = itemModels.objects.all()
context = {'posts': queryset}
return Response(context)
to
def list(self, request):
queryset = itemModels.objects.order_by('id').all()
context = {'posts': queryset}
return Response(context)
credit for #snakecharmerb thanks

Related

How can I update specific field after retrieved in django rest framework

How can I update specific field after retrieved in django rest framework
# Models.py
class Article(models.Model):
title = models.CharField(max_length=255)
body = models.TextField()
view = models.IntegerField(default=0)
def __str__(self):
return self.title
I want to update view after read a specific data.
# Views.py
class ArticleDetail(generics.RetrieveUpdateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
# Update view + 1
# serializers.py
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = "__all__"
Please help me
If you want your field to be incremented only on a GET request, you can update it in the retrieve method:
# views.py
class ArticleDetail(generics.RetrieveUpdateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
instance.view = instance.view + 1
instance.save()
serializer = self.get_serializer(instance)
return Response(serializer.data)
If you want it to be incremented with both GET and PATCH, you could update it in get_object instead:
# views.py
class ArticleDetail(generics.RetrieveUpdateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def get_object(self):
instance = super(ArticleDetail, self).get_object()
instance.view = instance.view + 1
instance.save()
return instance

How to use multiple lookup fields in Django Rest framework in a class based view?

I literally searched similar questions but didn't a answer that solves my question
I want a functionality like a question can have multiple answers
my models.py
class QuestionModel(models.Model):
question = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
doubt_class_id = models.ForeignKey(DoubtClasses, on_delete=models.CASCADE)
conceptual_class_id = models.ForeignKey(LiveClass_details, on_delete=models.CASCADE, null=True, blank=True)
status = models.BooleanField(default=False)
mentor = models.ForeignKey(Mentor, on_delete=models.CASCADE, null=True, blank=True)
def __str__(self):
return self.question
def clean(self):
if self.doubt_class_id and self.conceptual_class_id :
raise ValidationError("only one field can be set")
class AnswersModel(models.Model):
answer = models.TextField()
question_id = models.ForeignKey(QuestionModel, on_delete=models.CASCADE)
my urls.py
path('questions/', views.QuestionModelView.as_view()),
path('questions/<int:id>/', views.QuestionModelViewID.as_view()),
path('questions/<int:id>/answer/', views.AnswerModel.as_view()),
my views.py
# Create your views here.
class QuestionModelView(mixins.ListModelMixin, mixins.CreateModelMixin,GenericAPIView):
queryset = models.QuestionModel.objects.all()
serializer_class = serializers.QuestionModel_serializer
permission_classes = [IsAuthenticated]
def get(self, request):
return self.list(request)
def post(self, request):
return self.create(request)
class QuestionModelViewID(mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin,GenericAPIView):
queryset = models.QuestionModel.objects.all()
serializer_class = serializers.QuestionModel_serializer
permission_classes = [IsAuthenticated]
lookup_field = 'id'
def get(self, request, id=None):
if id:
return self.retrieve(request, id)
else:
return Response(status=status.HTTP_204_NO_CONTENT)
def put(self, request, id=None):
if int(request.POST.get('author')) != self.request.user.id:
return Response("you cannot edit othe user question", status=status.HTTP_405_METHOD_NOT_ALLOWED)
if id:
return self.update(request, id)
else:
return Response(status=status.HTTP_204_NO_CONTENT)
def delete(self, request, id=None):
if int(request.POST.get('author')) != self.request.user.id:
return Response("you cannot destroy othe user question", status=status.HTTP_405_METHOD_NOT_ALLOWED)
if id:
return self.delete(request, id)
else:
return Response(status=status.HTTP_204_NO_CONTENT)
class AnswerModel(mixins.ListModelMixin, mixins.CreateModelMixin, GenericAPIView):
lookup_field = 'id'
serializer_class = serializers.AnswerModel_serializer
def get_queryset(self, *args, **kwargs):
return models.AnswersModel.objects.filter(question_id = self.kwargs['id'])
def get(self, request, id=None):
return self.list(request)
def post(self, request, id=None):
if request.user.is_superuser:
return self.create(request, id)
else:
return Response("only superuser can post a answer", status=status.HTTP_400_BAD_REQUEST)
I want to make a url like questions/id/answers/answer_id where id is the question id and answer_id is the id for a particular answer as a question can have multiple answers but for that i want to add 2 lookup_fields in my view which i am not getting how to add it or please suggest another approach for this query if its not possible to do like that
if you have query like this questions/id/answers/answer_id
you can do like this if I understood your question good.
def get_queryset(self):
id = self.kwargs['id']
answerid = self.kwargs['answer_id']
queryset = Model.objects.get(
id=id,answerid=answerid)
return queryset
or
def get(self, request, id, answer_id):
Questiomn = Model.objects.get(
id=id,answerid=answerid)

How to use pre_save methods in rest_framework serializers?

I know this is a noob question about DRF. I use latest version of Django and DRF. In my Django , I create slugs in a method using pre_save signals.
def create_slug(instance, new_slug=None):
slug = slugify(instance.title)
if new_slug is not None:
slug = new_slug
qs = Article.objects.filter(slug=slug).order_by("-id")
exists = qs.exists()
if exists:
new_slug = "%s-%s" %(slug, qs.first().id)
return create_slug(instance, new_slug = new_slug)
return slug
#receiver(pre_save, sender = Article)
def pre_save_article_receiver(sender, instance, raw, using, **kwargs):
if not instance.slug:
instance.slug = create_slug(instance)
pre_save.connect(pre_save_article_receiver, sender=Article)
Then I can manage to write my views and serializers using DRF
from rest_framework import serializers
from yogavidya.apps.articles.models import Article
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = [
"title",
"user",
"content",
"excerpt",
]
--views.py--
app_name = 'articles'
class ArticleListView(generics.ListCreateAPIView):
lookup_field = 'pk'
serializer_class = ArticleSerializer
queryset = Article.objects.all()
def list(self, request):
# Note the use of `get_queryset()` instead of `self.queryset`
queryset = self.get_queryset()
serializer = ArticleSerializer(queryset, many=True)
print(serializer.data)
return Response(serializer.data)
def get_queryset(self):
return Article.objects.all()
def get_object(self):
pk = self.kwargs.get("pk")
return Article.objects.get(pk=pk)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
class ArticleViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
queryset = Article.objects.all().order_by('-title')
serializer_class = ArticleSerializer
When I post my form I get name 'create_slug' is not defined. Where is best place to override my save method and updates? can you help me ?
Thanks
I guess error is due to the wrong indentation of def create_slug
Class Xyz:
...
...
def create_slug(instance, new_slug=None):
slug = slugify(instance.title)
if new_slug is not None:
slug = new_slug
qs = Article.objects.filter(slug=slug).order_by("-id")
exists = qs.exists()
if exists:
new_slug = "%s-%s" %(slug, qs.first().id)
return create_slug(instance, new_slug = new_slug)
return slug
It is not a class function, so it should be outside class.

How do I get my Django generic view to work

Am I going about this the right way? Having never used 'generic views' I am tying to use Django's generic.UpdateView view. When I 'hit' the 'update' button on the form, I get an invalid form response with message 'Library with this Slide name already exists'
Grateful for any help.
View:
class Slideview(generic.UpdateView):
model = Library
template_name = 'app1/slide_update.html'
fields = ['slide_name', 'reference_value','esd',
'current_mean', 'counts_averaged', 'status']
context_object_name = 'qc_slide'
#def get_queryset(self):
#slide_id = self.kwargs['pk']
#return Library.objects.filter(slide_name=slide_id)
def get_success_url(self):
return reverse('Slideview', args=[self.kwargs['pk']])
def get_context_data(self, **kwargs):
context = super(Slideview, self).get_context_data(**kwargs)
#form = self.get_form(self.get_form_class())
#context['form'] = form
return context
def post(self, request, *args, **kwargs):
print("Im in post")
form = self.get_form(self.get_form_class())
if form.is_valid():
#Code will go here which will query a second model
#perform a series of math calculations and then
#return the updated information
self.object = self.get_object()
self.object.save()
return self.form_valid(form)
else:
print("Form not valid")
self.object = self.get_object()
return self.form_invalid(form)
Model:
class Library(models.Model):
slide_name = models.CharField(max_length=5, primary_key=True)
reference_value = models.DecimalField(max_digits=5, decimal_places=2, default=Decimal(0))
esd = models.DecimalField(max_digits=5, decimal_places=2, default=Decimal(0))
current_mean = models.DecimalField(max_digits=5, decimal_places=2, default=Decimal(0))
counts_averaged = models.IntegerField(default=0)
status = models.CharField(max_length=9)
def __str__(self):
return self.slide_name

Django update ViewSet

Currently I am developing a image gallery django project. The user can upload images, and later upload a 'result' to each of the images.
I know that I have to override the update(...) function, but I think I need help here with the Base64ImageFiled.
Step by step:
User uploads image (result = null)
Image gets stored in cloud
User uploads result to a specified image (need help here)
Here is my current structure:
class Image(models.Model):
project = models.ForeignKey(Project)
image = models.ImageField(upload_to='images')
result = models.ImageField(upload_to='results')
class ImageSerializer(serializers.ModelSerializer):
project = ProjectSerializer(read_only=True, required=False)
image = Base64ImageField(max_length=None, use_url=False)
result = Base64ImageField(max_length=None, use_url=False, required=False)
class ProjectImagesViewSet(viewsets.ViewSet):
queryset = Image.objects.select_related('project').all()
serializer_class = ImageSerializer
def list(self, request, project_pk=None):
queryset = self.queryset.filter( project__name = project_pk)
serializer = self.serializer_class(queryset, many=True)
return Response(serializer.data)
def update(self, request, pk=None, project_pk=None):
print(request.data['result'])
???
Django Rest Framework convention is to use partial_update instead of update (PATCH request method). If you will send PATCH request with image to the same url as for retrieve url is should get updated. if you require additional features on update then you can define:
class ProjectImagesViewSet(viewsets.ViewSet):
#.....
def partial_update(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.serialize(instance, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
#.... Your code ....
serializer.save()
return Response(serializer.data)
EDIT:
Try those changes:
class ImageSerializer(serializers.ModelSerializer):
project = ProjectSerializer(read_only=True, required=False)
image = Base64ImageField(max_length=None, use_url=False)
result = Base64ImageField(max_length=None, use_url=False, required=False)
class Meta:
model = Image
class ProjectImagesViewSet(viewsets.ViewSet):
queryset = Image.objects.select_related('project').all()
serializer_class = ImageSerializer
def list(self, request, project_pk=None):
queryset = self.queryset.filter(project__name=project_pk)
serializer = self.serializer_class(queryset, many=True)
return Response(serializer.data)
def update(self, request, pk=None, project_pk=None):
print(request.data['result'])
def partial_update(self, request, *args, **kwargs):
instance = self.queryset.get(pk=kwargs.get('pk'))
serializer = self.serializer_class(instance, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)