Am trying to write update view,but got an error please help me to find the problem,thanks :)
At first I have many to many field in my model.It is my model
class Portfolio(models.Model):
name = models.CharField(max_length=50, unique=True, blank=False, null=True)
market = models.ForeignKey(Market, on_delete=models.DO_NOTHING, related_name='market')
investor = models.ForeignKey('accounts.User', on_delete=models.DO_NOTHING, related_name='investor')
assets = models.ManyToManyField(Assets, related_name='assets')
def __str__(self):
return self.name
After that I have a serializer for my view:
class PortfolioSerializer(serializers.ModelSerializer):
class Meta:
model = Portfolio
fields = ['name', 'market', 'investor', 'assets']
And it's my view:
class PortfolioUpdateView(APIView):
serializer_class = PortfolioSerializer
def put(self, request, *args,):
data = request.data
portfo = Portfolio.objects.get(id=id)
print(portfo)
serilize = self.serializer_class(instance=request.user, data=request.POST)
if serilize.is_valid():
name = serilize.data['name']
market = Market.objects.get(pk=int(request.POST.get('market', '')))
assets = Assets.objects.get(pk=int(request.POST.get('assets', '')))
Portfolio.objects.update(name=name, market=market,
assets=assets,
)
return portfo
else:
pass
and at the end it is my error:
TypeError at /market/update/1
put() got an unexpected keyword argument 'id'
I found the answer by my self,because I needed to use id for get obj so I used request.data that is body's data of object include obj's id and added query-set method for getting the class objs
class PortfolioUpdateView(viewsets.ModelViewSet):
serializer_class = PortfolioSerializer
def get_queryset(self):
portfolio = Portfolio.objects.all()
return portfolio
def put(self, request, *args, **kwargs):
data = Portfolio.objects.get(id=request.data['id'])
update_portfolio = Portfolio.objects.update(name=data['name']
, market=Market.objects.get(pk=int(request.POST.get('market', ''))))
update_portfolio.save()
for asset in data['assets']:
asset_obj = Assets.objects.update(asset_name=asset['asset_name'])
update_portfolio.assets.add(asset_obj)
serializer = PortfolioSerializer(update_portfolio)
return Response(serializer.data)
And this is the URL
router.register("update", PortfolioUpdateView, basename="update")
Related
i was able to post the image but don't know why i am not able to update the image , i am using default form provided by DRF
i did not find any solutions yet for this one
i am uploading image via cloudinary api
the error
{
"image_1": [
"The submitted data was not a file. Check the encoding type on the form."
],
"image_2": [
"The submitted data was not a file. Check the encoding type on the form."
]
}
Model:
class MyDetail(models.Model):
name=models.CharField(max_length=50, null=True, blank=True)
image_1=models.URLField(null=True, blank=True)
image_2=models.URLField(null=True, blank=True)
Views:
class SingleDetailView(generics.RetrieveUpdateDestroyAPIView):
queryset=MyDetail.objects.all()
serializer_class = SingleDetailSerializer
lookup_field='id'
def update(self, request, *args, **kwargs):
instance = self.get_object()
image_1 = request.FILES.get('image_1',None)
image_2 = request.FILES.get('image_2',None)
if image_1:
uploaded_image_1 = cloudinary.uploader.upload(image_1)
request.data['image_1'] = uploaded_image_1['secure_url']
if image_2:
uploaded_image_2 = cloudinary.uploader.upload(image_2)
request.data['image_2'] = uploaded_image_2['secure_url']
serializer = self.get_serializer(instance, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
return Response({"message": "Updated successfully.", "data": serializer.data})
def perform_update(self, serializer):
serializer.save()
serializer:
class SingleDetailSerializer(serializers.ModelSerializer):
image_1 = serializers.ImageField(max_length=None,use_url=True,required=False)
image_2 = serializers.ImageField (max_length=None,use_url=True,required=False)
class Meta:
model = MyDetail
fields = ['id','name','image_1','image_2']
def to_representation(self, instance):
representation = super().to_representation(instance)
representation['image_1'] = instance.image_1
representation['image_2'] = instance.image_2
return representation
my DRF Form image
i even tried from my react form but it was still not working , i was not able to find solutions online and i don't know why it is not able to recognize the file though i uploaded the file. Help me to fix this
Here is how i solved it
Instead of updating image through views , i updated image directly serializer where i modified the url field to image field to upload the image
views :
class SingleDetailView(generics.RetrieveUpdateDestroyAPIView):
queryset=MyDetail.objects.all()
serializer_class = SingleDetailSerializer
lookup_field='id'
serializer :
class SingleDetailSerializer(serializers.ModelSerializer):
image_1 = serializers.ImageField(use_url=True, required=False)
image_2 = serializers.ImageField(use_url=True, required=False)
class Meta:
model = MyDetail
fields = ['id','name','image_1','image_2']
def to_representation(self, instance):
representation = super().to_representation(instance)
representation['image_1'] = instance.image_1
representation['image_2'] = instance.image_2
return representation
def update(self, instance, validated_data):
image_1 = validated_data.get('image_1',None)
image_2 = validated_data.get('image_2',None)
if image_1:
uploaded_image_1 = cloudinary.uploader.upload(image_1)
validated_data['image_1'] = uploaded_image_1['secure_url']
if image_2:
uploaded_image_2 = cloudinary.uploader.upload(image_2)
validated_data['image_2'] = uploaded_image_2['secure_url']
instance = super().update(instance, validated_data)
return instance
I'm trying to create an Odoo module which override Sales order confirm button. I followed the information I found, and I created the following code, but it doesn't work.
from odoo import models, fields, api
import logging
_logger = logging.getLogger(__name__)
class saleoverride(models.Model):
_name = 'saleoverride.saleoverride'
_description = 'saleoverride'
_inherit = 'sale.order'
name = fields.Char()
# value = fields.Integer()
# value2 = fields.Float(compute="_value_pc", store=True)
description = fields.Text()
transaction_ids = fields.Many2many('payment.transaction', 'saleoverride_transaction_rel', 'saleoverride_id', 'transaction_id',
string='Transactions', copy=False, readonly=True)
tag_ids = fields.Many2many('crm.tag', 'saleoverride_tag_rel', 'saleoverride_id', 'tag_id', string='Tags')
#api.model
def action_confirm(self):
res = super(SaleOrder, self).action_confirm()
_logger.info("saleoverride_action_confirm")
_logger.info(self)
return res
I tried to search the message in the log file, but can't find anything. Can someone help me?
Thanks!
The problem is that you are not extending the sale.order model, but creating a new one (saleoverride.saleoverride) based on sale.order.
Check odoo docs: Inheritance and extension
from odoo import models, fields, api
import logging
_logger = logging.getLogger(__name__)
class saleoverride(models.Model):
_description = 'saleoverride'
_inherit = 'sale.order'
name = fields.Char()
# value = fields.Integer()
# value2 = fields.Float(compute="_value_pc", store=True)
description = fields.Text()
transaction_ids = fields.Many2many('payment.transaction', 'saleoverride_transaction_rel', 'saleoverride_id', 'transaction_id',
string='Transactions', copy=False, readonly=True)
tag_ids = fields.Many2many('crm.tag', 'saleoverride_tag_rel', 'saleoverride_id', 'tag_id', string='Tags')
def action_confirm(self):
res = super(SaleOrder, self).action_confirm()
_logger.info("saleoverride_action_confirm")
_logger.info(self)
return res
Removing _name = 'saleoverride.saleoverride' from your class adds new features to sale.order.
Also remove the decorator since the original function doesn't have one.
When you want to override the code in addons, all you can do is just inheriting it. So, you can't define name while overriding the existing code.
Remove:
_name ='saleoverride.saleoverride'
I'm trying to found how Restframework's permission work , so i try write some code that response a simple Json. But the existence or absence of a ā€¨permission_classes does not affect the execution of the code and endpoint will response all request without checking any permission.
here is my code:
class TeacherStatisticPost(generics.RetrieveAPIView):
permission_classes = (ClassOwnerPermission)
queryset = ClassRoom.objects.all()
lookup_field = "id"
lookup_url_kwarg = 'classRoom_id'
def get_klass(self):
class_id = self.kwargs['classRoom_id']
return ClassRoom.objects.get(id=classRoom_id)
def get(self, request, *arg, **kwargs):
klass = self.get_klass()
response ={
'class_room_grade' : klass.grade,
'class_room_name' : klass.name,
}
return JsonResponse(response, safe=False)
and here is my permission.py:
class ClassOwnerPermission(permissions.BasePermission):
def has_perm(self, user, klass):
print("now in class perm") # never print out any thing!
return klass.owner == user
def has_object_permission(self, request, view, obj): # where is come from 'obj' ?
return self.has_perm(request.user, obj)
im try to set permission that just owner of ClassRoom can access to this endpoint.
Firstly, DRF expects permission_classes to be list or tuple. permission_classes at the line permission_classes = (ClassOwnerPermission) is not neither tuple not list. Put comma after the ClassOwnerPermission.
The line permission_classes = (ClassOwnerPermission, ) should work.
Secondly, you do not use get_object method which checks the permissions. Remove def get_klass(self): method and use get_object
Your view should look like following:
class TeacherStatisticPost(generics.RetrieveAPIView):
permission_classes = (ClassOwnerPermission, )
queryset = ClassRoom.objects.all()
lookup_field = "id"
lookup_url_kwarg = 'classRoom_id'
def get(self, request, *arg, **kwargs):
klass = self.get_object()
response ={
'class_room_grade' : klass.grade,
'class_room_name' : klass.name,
}
return JsonResponse(response, safe=False)
How can I write my own permission class for POST requests when using ModelViewSet?
I already tried to write my own permission_classe with no success. Even if my permission class is returning false it is still granting access to the post request
models.py
class Building(models.Model, HitCountMixin):
user = models.ForeignKey(User, on_delete=models.CASCADE) limit_choices_to=Q(country=2921044) | Q(country=798544), on_delete=models.SET_NULL) #<------------ Eltern Element
name = models.CharField(max_length=200, null=True, blank=True)
description = models.TextField(max_length=2000,null=True, blank=True)
facilities = models.TextField(max_length=2000, null=True, blank=True)
...
views.py
class BuildingImageViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows groups to be viewed or edited.
"""
serializer_class = BuildingImageSerializer
permission_classes = (permissions.IsAuthenticated, IsOwner,)
def get_queryset(self):
if self.request.user.is_authenticated:
return BuildingImage.objects.filter(building__user=self.request.user)
return None
permissions.py
class IsOwner(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
print("TEST")
return False
urls.py
router = routers.DefaultRouter()
router.register(r'buildingimages', myrest_views.BuildingImageViewSet, base_name="buildingimage")
If I I try to upload an image it is working, Why?
My IsOwner permission class is evaluated because I can see the print line with "TEST" in the console.
MY SOLUTION:
def has_permission(self, request, view):
if view.action == 'create':
building_url = request.POST.get('building')
building_path = urlparse(building_url).path
building_id = resolve(building_path).kwargs['pk']
building = Building.objects.get(id=building_id)
return building.user == request.user
return True
Pass list of classes, you used has_object_permission(), You need to write code inside has_permission() method.
permission_classes = [<class 'rest_framework.permissions.AllowAny'>]
you have to pass class that derive BasePermission class
permission.py
from rest_framework import permissions
class IsOwner(permissions.BasePermission):
def has_permission(self, request, view):
if <CONDITION>:
return True
else:
return False
The code is short and simple:
class Contact:
all_contacts = []
def __init__(self, name, email):
self.name = name
self.email = email
Contact.all_contacts.append(self)
c1 = Contact("Paul", "something#hotmail.com")
c2 = Contact("Darren", "another_thing#hotmail.com")
c3 = Contact("Jennie", "different#hotmail.com")
for i in Contact.all_contacts:
print(i)
Clearly all I want to do is print the 'all_contacts' list with the info I have added, but what I get is:
<__main__.Contact object at 0x2ccf70>
<__main__.Contact object at 0x2ccf90>
<__main__.Contact object at 0x2ccfd0>
What am I doing wrong?
Add the following to your Contact class:
class Contact:
...
def __str__(self):
return '%s <%s>' % (self.name, self.email)
This will tell Python how to render your object in a human-readable string representation.
Reference information for str
The __repr__ and __str__ methods for Contact aren't defined, so you get this default string representation instead.
def __str__(self):
return '<Contact %s, %s>' % (self.name, self.email)
Separate the container from the items stored in the container.
Add a __str__() method to Contact.
class Contact:
def __init__(self, name, email):
self.name = name
self.email = email
def __str__(self):
return "{} <{}>".format(self.name, self.email)
class ContactList(list):
def add_contact(self, *args):
self.append(Contact(*args))
c = ContactList()
c.add_contact("Paul", "something#hotmail.com")
c.add_contact("Darren", "another_thing#hotmail.com")
c.add_contact("Jennie", "different#hotmail.com")
for i in c:
print(i)