drf post file to database - pdf

MODELS.PY
class MyFile(models.Model):
id = models.AutoField(primary_key=True)
in_file = models.FileField(upload_to=join_path('front/files', 'input'))
def __str__(self):
return self.in_file.name[18:]
SERIALIZERS.PY
class MyFileSerializer(serializers.ModelSerializer):
in_file = serializers.FileField(
max_length = 10000000,
allow_empty_file = False,
use_url = False,
)
class Meta:
model = MyFile
fields = ['in_file']
def create(self, validated_data):
file = validated_data.pop('in_file')
return MyFile.objects.create(in_file=file)
class DocumentChangeAPIView(APIView):
parser_classes = (FileUploadParser, FormParser)
def post(self, request):
serializer = MyFileSerializer(data=request.data)
print(request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(serializer.data)
enter image description here
printing this response
{'file': <InMemoryUploadedFile: samandar_resume.pdf (multipart/form-data; boundary=--------------------------689093269296817855921257)>}

Related

DRF- how to do many readonly and writeonly fields in serializers

I used two foreignkey in my model. I want to show those fields name when we give get request I have tried but its worked only one fields not rest one.
models.py
class Organization(models.Model):
code = models.CharField(max_length=25, null=False, unique=True)
name = models.CharField(max_length=100, null=False)
location = models.ForeignKey(Location, on_delete=models.RESTRICT)
mol_number = models.CharField(max_length=100)
corporate_id = models.CharField(max_length=100)
corporate_name = models.CharField(max_length=100)
routing_code = models.CharField(max_length=100)
iban = models.CharField(max_length=100)
description = models.TextField()
total_of_visas = models.IntegerField(null=False, default=0)
base_currency = models.ForeignKey(Currency, on_delete=models.RESTRICT)
def __str__(self):
return self.name
serializers.py
class OrganizationSerializer(serializers.ModelSerializer):
location = serializers.CharField(read_only=True, source="location.name")
base_currency = serializers.CharField(read_only=True, source="base_currency.currency")
location_id = serializers.IntegerField(write_only=True, source="country.id")
base_currency_id = serializers.IntegerField(write_only=True, source="base_currency.id")
class Meta:
model = Organization
fields = ["id", "name", "location", "mol_number", "corporate_id", "corporate_name",
"routing_code", "iban", "description", "total_of_visas", "base_currency",
"location_id", "base_currency_id"]
def create(self, validated_data):
...
def update(self, instance, validated_data):
...
How can I access those two fields???.. Anyhelp Appreciable..
you can override the to_representation method
def to_representation(self, instance):
....
so something like this:
class OrganizationSerializer(serializers.ModelSerializer):
...
class Meta:
...
def to_representation(self, instance):
rep = super(OrganizationSerializer, self).to_representation(instance)
rep['location'] = instance.location.name //the .name is the field in the //location model that you want to return it can be anything in the model
rep['base_currency'] = instance.base_currency.currency
rep['location_id'] = instance.location_id.country.id
rep['base_currency_id'] = instance.base_currency_id.base_currency_id
return rep
def create(self, validated_data):
...
def update(self, instance, validated_data):

Django | I'd like to delete a product and all of its related data from the database

I have a shopping cart with some items in it. If I delete a product from the basket, I also want to remove it from the ordered item. I am now unable to delete the order items and quantity. I am using ajax to remove items from the cart.
class Cart(models.Model):
user = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
products = models.ManyToManyField(Product, blank=True)
subtotal = models.DecimalField(default = 0.00, max_digits=100, decimal_places=2)
total = models.DecimalField(default = 0.00, max_digits=100, decimal_places=2)
updated = models.DateTimeField(auto_now=True)
timestamp = models.DateTimeField(auto_now_add=True)
objects = CartManager()
def __str__(self):
return str(self.id)
class OrderItem(models.Model):
Quantity_Choices =(
('one', '1'),
('Two', '2'),
('Three', '3'),
)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
cart = models.ForeignKey(Cart, on_delete=models.CASCADE)
quantity = models.CharField(max_length=22, choices=Quantity_Choices, null=True, blank=True)
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.id)
class CartManager(models.Manager):
def new_or_get(self, request):
cart_id = request.session.get("cart_id", None)
qs = self.get_queryset().filter(id=cart_id)
if qs.count() ==1:
new_obj = False
cart_obj = qs.first()
if request.user.is_authenticated and cart_obj.user is None:
cart_obj.user = request.user
cart_obj.save()
else:
cart_obj = Cart.objects.new(user=request.user)
new_obj = True
request.session['cart_id'] = cart_obj.id
return cart_obj, new_obj
def new(self, user=None):
user_obj = None
if user is not None:
if user.is_authenticated:
user_obj = user
return self.model.objects.create(user=user_obj)
The code for adding an item to the cart is as follows.
def cart_update(request):
product_id = request.POST.get('product_id')
print(product_id)
if product_id is not None:
try:
product_obj = Product.objects.get(id=product_id)
except Product.DoesNotExist:
print("No product")
return render("cart_home")
cart_obj, new_obj = Cart.objects.new_or_get(request)
if product_obj in cart_obj.products.all():
cart_obj.products.remove(product_obj)
added= False
else:
cart_obj.products.add(product_obj)
added =True
request.session['cart_items'] = cart_obj.products.count()
if request.is_ajax():
print("ajax request")
json_data = {
"added":added,
"removed": not added,
"cartItemCount":cart_obj.products.count()
}
return JsonResponse(json_data)
return redirect("cart_home")
def productdetails(request, pk):
product = Product.objects.get(id=pk)
cart, cart_created= Cart.objects.get_or_create(request)
form =sizeForm(instance=product)
if request.method =='POST':
form = sizeForm(request.POST, instance =product)
if form.is_valid():
quantity=form.cleaned_data.get('quantity')
print(quantity)
orderitem, created = OrderItem.objects.get_or_create(product=product,cart=cart, quantity=quantity)
context= {
'object' : product,
'form':form
}
return render(request, 'home/productdetails.html', context)
orderitem
cart

How to solve TypeError: Object of type 'Category' is not JSON serializable

I have 3 tables (Book,Author,Category)
when I try to get a list of books or authors I have this error: TypeError: Object of type 'Category' is not JSON serializable. I think it's related to the relationship with the category table. Could you please check my models is it structure well or not and how can I solve this issue.
__tablename__ = 'author'
id = db.Column(db.Integer().with_variant(Integer, "sqlite"), primary_key=True)
auth_nam = db.Column(db.String, nullable=False)
gender = db.Column(db.String, nullable=True)
count_book = db.Column(db.Integer,nullable=False)
category=db.relationship('Category', backref='author', lazy=True)
def __init__(self,auth_nam,gender,count_book,category):
self.auth_nam = auth_nam
self.gender = gender
self.count_book = count_book
self.category = category
def insert(self):
db.session.add(self)
db.session.commit()
def update(self):
db.session.commit()
def delete(self):
db.session.delete(self)
db.session.commit()
def format(self):
return {
'id': self.id,
'auth_nam': self.auth_nam,
'gender': self.gender,
'count_book': self.count_book,
'category': self.category
}
'''
Books
'''
class Book(db.Model):
__tablename__='book'
id = db.Column(db.Integer().with_variant(Integer, "sqlite"), primary_key=True)
book_name=db.Column(db.String,nullable=False)
book_issue=db.Column(db.DateTime,nullable=False)
category=db.relationship('Category', backref='book', lazy=True)
def __init__(self, book_name, book_issue, category):
db.create_all()
self.book_name = book_name
self.book_issue = book_issue
self.category = category
def insert(self):
db.session.add(self)
db.session.commit()
def update(self):
db.session.commit()
def delete(self):
db.session.delete(self)
db.session.commit()
def format(self):
return {
'id': self.id,
'book_name': self.book_name,
'book_issue': self.book_issue,
'category': self.category,
}
'''
Category
'''
class Category(db.Model):
__tablename__ = 'category'
id = Column(db.Integer, primary_key=True)
name = Column(db.String,nullable=False)
book_id = db.Column(db.Integer, db.ForeignKey('book.id'),nullable=False)
author_id = db.Column(db.Integer, db.ForeignKey('author.id'),nullable=False)
def __init__(self, name, book_id, author_id):
self.name = name
self.book_id = book_id
self.author_id = author_id
def insert(self):
db.session.add(self)
db.session.commit()
def update(self):
db.session.commit()
def delete(self):
db.session.delete(self)
db.session.commit()
def format(self):
return {
'id': self.id,
'name': self.name,
'book_id': self.book_id,
'author_id': self.author_id,
}
def format(self):
return {
'id': self.id,
'book_name': self.book_name,
'book_issue': self.book_issue,
'category': self.category,
}
'''
Category
'''
class Category(db.Model):
__tablename__ = 'category'
id = Column(db.Integer, primary_key=True)
name = Column(db.String,nullable=False)
book_id = db.Column(db.Integer, db.ForeignKey('book.id'),nullable=False)
author_id = db.Column(db.Integer, db.ForeignKey('author.id'),nullable=False)
def __init__(self, name, book_id, author_id):
self.name = name
self.book_id = book_id
self.author_id = author_id
def insert(self):
db.session.add(self)
db.session.commit()
def update(self):
db.session.commit()
def delete(self):
db.session.delete(self)
db.session.commit()
def format(self):
return {
'id': self.id,
'name': self.name,
'book_id': self.book_id,
'author_id': self.author_id,
}
app.py:
#app.route('/books', methods=['GET'])
def get_books():
books = Book.query.all()
books_formated=[book.format() for book in books]
return jsonify({
"success": True,
"books":books_formated
})
Since you have set the category as a relationship attribute on Book model, when you call this line in your Book.format():
'category': self.category
the self.category will return the related Category instance, it's a Python object. However, the Python object is not JSON serializable, that's why you got TypeError: Object of type 'Category' is not JSON serializable. when jsonify() was called.
To solve this, you can either change self.category to 'category': [category.name for category in self.category] (get the string of the category name) or 'category': [category.format() for category in self.category] (get the dict of the category data). Both string and dict are JSON serializable.

ItemLoader doesn't pass the loader context to input processors

my spider: autospd.py
class AutospdSpider(scrapy.Spider):
name = 'autospd'
start_urls = ['http://news.dayoo.com/guangzhou/150960_2.shtml']
dt_ft = "%Y-%m-%d %H:%M"
def parse(self, response):
list_objs = response.css("div.dy-list>div")
for li in list_objs:
loader = AutopjtItemLoader(item=AutopjtItem(), selector=li, context=self.dt_ft)
print(loader.context.items()) #please see print-1
loader.nested_css("h2>a").add_css("title", "::text")
loader.nested_css("h2>a").add_css("url", "::attr(href)")
loader.nested_css("div.txt-area>div.news-time").add_xpath("pub_time", "string()")
yield loader.load_item()
print-1: dict_items([('context', '%Y-%m-%d %H:%M'), ('selector',
\r\n '>), ('response', None), ('item',
{}) ])
items.py
def func(value, loader_context):
print(loader_context.items()) # please see print-2
# ft = loader_context.get("context")
# time_dt = datetime.strptime(value, ft)
return value
class AutopjtItemLoader(ItemLoader):
default_output_processor = TakeFirst()
pub_time_in = MapCompose(func)
class AutopjtItem(scrapy.Item):
title = scrapy.Field()
url = scrapy.Field()
pub_time = scrapy.Field()
print-2: [('selector', [2019-06-12 08:59< '>]), ('response',
None), ('item', {})]
Why don't have "context" in loader_context?
def nested_xpath(self, xpath, **context):
selector = self.selector.xpath(xpath)
context.update(selector=selector)
subloader = self.__class__(
item=self.item, parent=self, **context
)
return subloader
def nested_css(self, css, **context):
selector = self.selector.css(css)
context.update(selector=selector)
subloader = self.__class__(
item=self.item, parent=self, **context
)
return subloader
From the scrapy's source code, if you use nested_css or nested_xpath, you must add your context. eg:
loader.nested_css("div.txt-area>div.news-time", dt_ft=self.dt_ft).add_xpath("pub_time", "string()")

DRF post to a field without showing it in the API form

I have a Django Rest Framework API. I want to have a field 'result' that is on the model, but not shown on the API form, yet still appears in the json when I list the data or view the detail.
So I want to see this on my POST form:
And this on my GET request:
How can this be done?
serialisers.py:
from rest_framework import serializers
from .models import Expression
class ExpressionSerializer(serializers.ModelSerializer):
def __init__(self, *args, **kwargs):
self.operator_mapping = {
"add": " + ",
"minus": " - ",
"divide": " / ",
"multiply": " * "
}
super(ExpressionSerializer, self).__init__(*args, **kwargs)
class Meta:
model = Expression
fields = ["expression", "result"]
def create(self, validated_data):
expression_obj = Expression.objects.create(**validated_data)
return expression_obj
def update(self, instance, validated_data):
instance.expression = validated_data.get('expression', instance.expression)
instance.result = validated_data.get('result', instance.result)
instance.save()
return instance
views.py:
from rest_framework import generics, status
from rest_framework.response import Response
from rest_framework.views import APIView
from lxml import etree
from .serialisers import ExpressionSerializer
from .models import Expression
class ExpressionAPIView(APIView):
def __init__(self):
self.operator_mapping = {
"add": " + ",
"minus": " - ",
"divide": " / ",
"multiply": " * "
}
self.queryset = Expression.objects.all()
self.serializer_class = ExpressionSerializer
def get(self, request):
return Response({'data': request.data})
def post(self, request):
root = etree.XML(request.data['expression'])
result = self.evaluate_expression(root)[0]
exp_parsed = self.expression_to_string(root) + f" = {result}"
serializer_data = {'expression': exp_parsed, 'result': result}
serializer = self.serializer_class(
data=serializer_data,
)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.validated_data, status=status.HTTP_201_CREATED)
def expression_to_string(self, root):
expression = ""
for child in root:
if child.tag != "root" and child.tag != "expression":
if child.tag == "number":
num = int(child.text)
if child != root[-1]:
expression += f"{num} {self.operator_mapping[root.tag]} "
else:
expression += f"{num}"
else:
if child != root[-1]:
expression += f"({self.expression_to_string(child)}) {self.operator_mapping[root.tag]} "
else:
expression += f"({self.expression_to_string(child)})"
else:
expression += f"{self.expression_to_string(child)}"
return expression
def evaluate_expression(self, root):
numbers = []
for child in root:
if child.tag == "number":
num = int(child.text)
numbers.append(num)
elif child.tag in ["add", "minus", "divide", "multiply"]:
_ = self.evaluate_expression(child)
def eval_sublist(_, operator):
x = _[0]
for i in range(1, len(_)):
x_str = f"{x}{operator}{_[i]}"
x = eval(x_str)
return x
numbers.append(eval_sublist(_, self.operator_mapping[child.tag]))
else:
numbers.extend(self.evaluate_expression(child))
return numbers
You can define the result field as being read only on your serializer.
That can be achieved through either defining the extra serializer parameters read_only_fields inside the Meta class or by explicitly defining the result field and adding a read_only=True flag to it.