How to store images like Images API - python

Hi this my model for create simple member already searched for several places and until now I haven't figured out how I can store the directory of my image next to my image field.
class Member(models.Model):
with open(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))+'/api/data/states.json') as s:
states_json = json.load(s)
STATES = [(str(state["nome"]), str(state["sigla"])) for state in states_json]
name = models.CharField(max_length=100, null=True, blank=True, verbose_name='Nome')
image = models.ForeignKey(
"wagtailimages.Image",
blank=False,
null=True,
related_name="+",
on_delete=models.SET_NULL,
verbose_name='Imagem do membro',
)
role = models.CharField(max_length=35, null=True, blank=True, verbose_name='Cargo')
city = models.CharField(max_length=30, null=True, blank=True, verbose_name='Cidade')
state = models.CharField(
verbose_name='Estado',
max_length=19,
choices=STATES,
default=('SP'),
)
created = models.DateField(default=timezone.now, verbose_name='Atualizado')
modified = models.DateField(default=timezone.now, verbose_name='Modificado')
panels = [
FieldPanel("name"),
ImageChooserPanel("image"),
FieldPanel("role"),
FieldPanel("city"),
FieldPanel("state"),
FieldPanel("created"),
FieldPanel("modified"),
]
def __str__(self):
return self.name
class Meta:
verbose_name = 'Membro'
verbose_name_plural = 'Membros'
This work normally but how to store image informations like Wagtail Images API?
Example:
"detail_url": "http://localhost/api/v2/images/2/",
"download_url": "/media/original_images/l8GlI3V.jpg"
This my JSON from API
[
{
"id": 6,
"name": "Gabriel",
"role": "Desenvolvedor",
"image": 4,
"city": "Itapetininga",
"state": "São Paulo",
"created": "2020-04-26",
"modified": "2020-04-26"
}
]
Thanks for help!!!

This is the link from the docs, Wagtail has a dependency of DRF, Create the serializer that you want and represent the image as a link instead of the pk, This should be straightforward (see DRF docs).
This video on custom serializers should help too.

Related

Calculate sum of model objects in django serializers

In my app, each user has his wallets in which he can save his daily expenses.
How can I get sum of money for each instance of wallet with many expenses saved to it?
I've tried serializers.SerializerMethodField()
from django.db.models import Sum
from django.db.models import Q
class WalletInstanceSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.id')
entry = BudgetEntrySerializer(many=True, read_only=True)
expense_sum = serializers.SerializerMethodField()
class Meta:
model = WalletInstance
fields = '__all__'
def get_expense_sum(self, obj):
return WalletInstance.objects.filter(Q(id=obj.id)|Q(entry__entry_type='income')).aggregate(Sum('entry__amount'))['entry__amount__sum']
And this gives me data in the correct format but the sum is wrong, for example
[
{
"id": "d458196e-49f1-42db-8bc2-ee1dba438953",
"owner": 1,
"entry": [
{
"id": 3,
"owner": 1,
"title": "dsfdsf",
"amount": 7,
"description": "sdfdsf",
"entry_type": "income",
"date_added": "2022-08-13",
"entry_category": {
"id": 2,
"name": "Transport"
}
},
{
"id": 4,
"owner": 1,
"title": "fesfvsdfgvbtdg",
"amount": 12,
"description": "efesf",
"entry_type": "income",
"date_added": "2022-08-13",
"entry_category": {
"id": 2,
"name": "Transport"
}
}
],
"viewable": [
"admin#gmail.com"
],
"expense_sum": 83,
"name": "dsdsds",
"date_added": "2022-08-13"
}
]
Expense_sum is 83 but amount fields are 7 and 12 so that's equal to 19
How can i get the correct number?
Models
class BudgetEntry(models.Model):
STATE= [
('income','income'),
('expenses','expenses'),
]
owner = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='owner_of_entry', on_delete=models.CASCADE)
title = models.CharField(max_length=20)
amount = models.IntegerField()
description = models.CharField(max_length=60, null=True)
entry_type = models.CharField(max_length=15, choices=STATE, null=True)
entry_category = models.ForeignKey(Category, null=True, blank=True, related_name='category_of_entry', on_delete=models.SET_NULL)
date_added = models.DateField(auto_now_add=True)
class WalletInstance(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True)
name = models.CharField(max_length=30, null=True)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='owner', on_delete=models.CASCADE)
viewable = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='can_view', blank=True)
entry = models.ManyToManyField(BudgetEntry, related_name='BudgetEntry', blank=True)
date_added = models.DateField(auto_now_add=True)
I think ORM query for the BudgetEntry is wrong. It should be like the following:
def get_expense_sum(self, obj):
return obj.entry.filter(entry_type='income').aggregate(Sum('entry__amount'))['entry__amount__sum']
I've figured it out. Firstly I've created #property in my database to get sum of expenses, but this wasn't very useful If I ever wanted to count income so I passed the value arg to the function where the value can be expense/income
class WalletInstance(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True)
name = models.CharField(max_length=30, null=True)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='owner', on_delete=models.CASCADE)
viewable = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='can_view', blank=True)
entry = models.ManyToManyField(BudgetEntry, related_name='BudgetEntry', blank=True)
date_added = models.DateField(auto_now_add=True)
def total_amount(self, value):
queryset = self.entry.filter(entry_type=value).aggregate(
total_amount=models.Sum('amount'))
return queryset["total_amount"]
And now I'm calling this function in my serializer instead of counting there
class WalletInstanceSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.id')
entry = BudgetEntrySerializer(many=True, read_only=True)
viewable = serializers.SlugRelatedField(many=True, queryset=get_user_model().objects.all(), slug_field='email')
expense_sum = serializers.SerializerMethodField()
class Meta:
model = WalletInstance
fields = '__all__'
def get_expense_sum(self, obj):
wallet_obj = WalletInstance.objects.get(id=obj.id)
return wallet_obj.total_amount('expenses')

Load data from model in view.py Django

I just started with Django and Python and I still don't understand it very well. Would it be possible to access all the information stored in Persons, showing also orderstext and archivename, I can't manage to do it :( my idea is to get all the information and save it as JSON, but I'm not getting the info from orderstext and archivename, it would be great if someone could show me the right way.
models.py
from django.db import models
class Order(models.Model):
order_id = models.PositiveIntegerField(blank=True, null=True)
orderstext = models.CharField(max_length=250, blank=True, null=True, )
order_start = models.DateTimeField(blank=True, null=True)
order_end = models.DateTimeField(blank=True, null=True)
#property
def default(self):
return self.orderstext
class Meta:
managed = False
db_table = 'order'
class Archives(models.Model):
archive_id = models.AutoField(primary_key=True, null=False)
archivename = models.CharField(max_length=50, unique=True, blank=True, null=True)
deleted = models.IntegerField(blank=True, null=True)
def __str__(self):
return self.archivename
#property
def default(self):
return self.archivename
class Meta:
managed = False
db_table = 'archives'
class Clients(models.Model):
name = models.CharField(max_length=20, verbose_name="Name")
lastname = models.CharField(max_length=50, blank=True, null=True, verbose_name="Lastname")
archives = models.ForeignKey('Archives', db_column='archive_id', on_delete=models.CASCADE, null=True, verbose_name="Archives")
order = models.ForeignKey('Order', db_column='order_id', on_delete=models.CASCADE, null=True, verbose_name="Order")
coments = models.CharField(max_length=250, blank=True, null=True, verbose_name="Coments")
class Meta:
managed = False
db_table = 'clients'
views.py
from django.http import JsonResponse
from .models import Clients
def data_json:
info = list(Clients.objects.all().values())
response = {'clients': info}
return JsonResponse(response)
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('clients-info/', views.data_json, name='data_json'),
]
JSON Response
{
"clients": {
"id": 4,
"name": "First",
"lastname": "Last Name",
"archive_id": 6,
"order_id": 3,
"coments": "No comments"
}
}
You can annotate..[Django-doc] the clients queryset with the orderstext and archivename along side F-expressions..[Django-doc] like this:
from django.db.models import F
Clients.objects.annotate(
archivename=F("archives__archivename"),
orderstext=F("order__orderstext"),
).values()
Although instead of using values I highly recommend using something like DRF serializers..[DRF-doc] to handle serialization of your data.
If I'm understanding correctly, you'd want to get a certain field data on the FK field on each client object, but what you're getting is the pk value of Order and Archive models on each Client objects.
{
"clients": {
"id": 4,
"name": "First",
"lastname": "Last Name",
"archive_id": 6, # foreign key pk field reference
"order_id": 3, # foreign key pk field reference
"coments": "No comments"
}
}
If I'm correct, then one approach you could use is to change the reference name to reference the fields orderstext and archivename respectively instead of order_id and archive_id.
So I wouldn't change anything else but just the two foreign key fields on the Client model. Updating the reference where db_column points:
class Clients(models.Model):
...
archives = models.ForeignKey('Archives', db_column='archivename', on_delete=models.CASCADE, null=True, verbose_name="Archives")
order = models.ForeignKey('Order', db_column='orderstext', on_delete=models.CASCADE, null=True, verbose_name="Order")
...
You can read more from the doc on db-column.
There're several answers in this 12-years old question. I believe more of one might solve your problem.
Below one example of solution:
from django.http import JsonResponse
from django.core.serializers import serialize
from .models import Clients
def data_json(request):
info = Clients.objects.all()
response = serialize('json', info)
return JsonResponse(response, safe=False)
I recommend you read the documentation about JSON request and response objects and serialization formats.

Error in making POST request to django API

From post man, I'm trying to make POST request to an order API created using django restframework but I'm getting the following error:
product = Product.objects.get(id=i['product'])
TypeError: string indices must be integers
The specific point where the error is located is specified in the error but I find difficulty constructing VALID json for the request body.
Here is how I'm making the request on postman:
{
"orderItems":{
"product": {"name":"abc", "brand":"def", "image"www.example.com/img", "description":"xyz", "price":"50"},
"qty":"2",
"price":"200"
},
"shippingAddress": {
"address":"abc", "city":"B", "postalCode":"12345",
},
"paymentMethod":"monify",
"itemPrice":"100"
}
Here is the program:
class Product(models.Model):
category = models.CharField(max_length=50, choices=Categories.choices, default=Categories.medications)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, related_name="user_product", null=True)
name = models.CharField(max_length=150)
brand = models.CharField(max_length=255, default="brand")
productClass = models.CharField(max_length=50, null=True, blank=True)
image = models.ImageField(upload_to="images/products/")
label = models.CharField(max_length=254, default='', blank=True, null=True)
price = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True)
stock = models.IntegerField(null=True, blank=True, default=0)
dateCreated = models.DateTimeField(auto_now_add=True)
class Order(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, related_name="user_order", null=True)
paymentMethod = models.CharField(max_length=200, null=True, blank=True)
dateCreated = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.dateCreated)
models.py
class OrderItem(models.Model):
product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True)
image = models.CharField(max_length=200, null=True, blank=True)
order = models.ForeignKey(Order, on_delete=models.SET_NULL, null=True)
name = models.CharField(max_length=200, null=True, blank=True)
qty = models.IntegerField(null=True, blank=True, default=0)
price = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True)
def __str__(self):
return str(self.name)
The view I', trying to test is shown below:
def addOrderItems(request):
user = request.user
data = request.data
orderItems = data['orderItems']
if orderItems and len(orderItems) == 0:
return Response({'detail': 'Order item was not provided'}, status=status.HTTP_400_BAD_REQUEST)
else:
# Step 1: Create order
order = Order.objects.create(
user=user,
paymentMethod=data['paymentMethod'],
)
#Step 2: Create shipping address
shipping = ShippingAddress.objects.create(
order=order,
address=data['shippingAddress']['address'],
)
# Step 3: Create order items, then set order to orderItem relationship
for i in orderItems:
product = Product.objects.get(id=i['product'])
item = OrderItem.objects.create(
product=product,
order=order,
name=product.name,
qty=i['qty'],
price=i['price'],
image=product.image.url,
)
# Step 4: Update stock
product.countInStock -= item.qty
product.save()
serializer = OrderSerializer(order, many=False)
return Response(serializer.data)
Any hint on this is well appreciated
I think the payload is not correct. Now the whole product data is uploaded, but it should be changed into the product_id. Because in the view, it is being considered as the id field like Product.objects.get(id=i['product']).
So the solution is like the following.
First, the payload should be changed.
{
"orderItems":[{
"product_id": 3, // here I changed
"qty":"2",
"price":"200"
}],
"shippingAddress": {
"address":"abc", "city":"B", "postalCode":"12345",
},
"paymentMethod":"monify",
"itemPrice":"100"
}
And in the addOrderItems function,
def addOrderItems(request):
...
if orderItems and len(orderItems) == 0:
...
else:
...
# Step 3: Create order items, then set order to orderItem relationship
for i in orderItems:
product = Product.objects.get(id=i['product_id'])
...
Your JSON is invalid (the "image" key in "orderItems" was messed up). To check this, you can use an online tool like https://jsonformatter.curiousconcept.com/.
Moreover, from the way you are iterating over it, orderItems should contain a list.
Here is the corrected JSON:
{
"orderItems": [{
"product": {"name":"abc", "brand":"def", "image": "www.example.com/img", "description":"xyz", "price":"50"},
"qty":"2",
"price":"200"
}],
"shippingAddress": {
"address":"abc", "city":"B", "postalCode":"12345",
},
"paymentMethod":"monify",
"itemPrice":"100"
}
In your Product model, you should also add an ID as PrimaryKey to be able to retrieve it later in your view:
import uuid
class Product(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
# ... (all your other attributes)
The JSON will then include this product ID:
{
"orderItems": [{
"product": {"id": "9b84820b-1b4f-43a2-b576-14c3e1635906", "name":"abc", "brand":"def", "image": "www.example.com/img", "description":"xyz", "price":"50"},
"qty":"2",
"price":"200"
}],
"shippingAddress": {
"address":"abc", "city":"B", "postalCode":"12345",
},
"paymentMethod":"monify",
"itemPrice":"100"
}
Then the line product = Product.objects.get(id=i['product']) should be replaced with:
product = Product.objects.get(id=i['product']['id'])

django rest framework get all related fields and filter in a manytomany field nested

I'm new in Django I want to get all informations of my contacts for a store given in parameter and all extra from another model.
Here is my code :
Models.py
class Store(models.Model):
name = models.CharField(max_length=100)
​
​
class Contact(models.Model):
id = models.CharField(primary_key=True, max_length=200)
first_name = models.CharField(max_length=100, null=True, blank=True)
last_name = models.CharField(max_length=100, null=True, blank=True)
email = models.CharField(max_length=100, null=True, blank=True)
stores = models.ManyToManyField(Store, related_name='contacts')
​
​
class DataType(models.Model):
datatype = models.CharField(max_length=10)
class DataField(models.Model):
name = models.CharField(max_length=100)
label = models.CharField(max_length=100)
datatype = models.ForeignKey(
'DataType',
on_delete=models.SET_NULL,
null=True
)
class DataFieldValue(models.Model):
contact = models.ForeignKey(
Contact,
on_delete=models.SET_NULL,
related_name='datafieldvalues',
null=True
)
datafield = models.ForeignKey(
'DataField',
on_delete=models.SET_NULL,
null=True
)
value = models.CharField(
max_length=250,
null=True,
blank=True
)
Views.py
# Contact API views.
class ContactListAPIView(generics.ListAPIView):
queryset = Contact.objects.all()
serializer_class = ContactSerializer
filter_class = ContactFilter
Filters.py
class ContactFilter(django_filters.rest_framework.FilterSet):
store = django_filters.CharFilter()
class Meta:
model = Contact
fields = ['store']
Serializers.py
class ContactSerializer(serializers.ModelSerializer):
class Meta:
model = Contact
fields = '__all__'
(Additionnal) Here is the schema :
schema
this is what i want:
GET /contacts/?store=54
{
"count": 25,
"next": "<url>/contacts/?page=3",
"previous": "<url>/contacts/?page=2",
"data": [
{
"id": "a519d2cd-13c6-48f3-b391-9a7e0cee58cc",
"src_id": 356,
"first_name": "Benjamin",
"last_name": "Pavard",
"email": "benjamin.pavard#email.fr",
"datafields" : {
"age" : "eighteen"
},
"store": 54
},
....
]
}
but this is what i got :
{
"next": null,
"previous": null,
"count": 10,
"data": [
{
"id": "1234567",
"first_name": null,
"last_name": null,
"email": "cartouche#email.fr",
},
.....
}
Questions :
how can i get the "datafields" ?
"age" is a "datafield" object and "eighteen" is a datafieldvalue object.
How can i get only the store that i've previously gave in parameter?
Thanks a lot for your help whatever it was.
You need to add more fields in the ContactSerializer
class ContactSerializer(serializers.ModelSerializer):
store = serializers.SerializerMethodField()
datafields = serializers.SerializerMethodField()
class Meta:
model = Contact
fields = '__all__'
def get_datafields(self, obj):
result = {}
for data_field_value in obj.datafieldvalues.all().select_related('datafield'):
result[data_field_value.datafield.label] = data_field_value.value
return result
def get_store(self, obj):
request = self.context['request']
store = request.query_params.get('store', '')
return store

Serialize model objects into a JSON dict using django-rest-framework

So if I have the following model class in Django:
class Person(models.Model):
name = models.CharField(max_length=250)
is_active = models.BooleanField(default=True)
address_line1 = models.CharField(max_length=100, blank=True, null=True)
address_line2 = models.CharField(max_length=100, blank=True, null=True)
town = models.CharField(max_length=100, blank=True, null=True)
county = models.CharField(max_length=100, blank=True, null=True)
post_code = models.CharField(max_length=100, blank=True, null=True)
and my goal is to serialize it into the following JSON:
{
"name": "Joe Bloggs",
"is_active": true,
"contact": {
"address1": "Bloggs House"
"address2": "1 Bloggs Lane",
"city": "Bloggs Town",
"county": "Bloggs Town",
"zip": "BL0 GG5",
"country": "UK"
}
}
I tried the following, but it didn't work and I'm pretty sure that's not how the serializers.ListField is meant to work (I think it's meant to be for a list of the same thing):
class MailChimpListSerializer(serializers.ModelSerializer):
class Meta:
model = Person
contact = serializers.DictField(
address1=serializers.CharField(source='address_line1'),
address2=serializers.CharField(source='address_line2'),
city=serializers.CharField(source='town'),
state=serializers.CharField(source='town', read_only=True),
zip=serializers.CharField(source='post_code'),
country=serializers.SerializerMethodField()
)
permission_reminder = serializers.SerializerMethodField()
campaign_defaults = serializers.DictField(
from_name=serializers.CharField(source='name'),
from_email=serializers.CharField(source='primary_contact_email'),
subject=serializers.CharField(),
language=serializers.CharField()
)
email_type_option = serializers.SerializerMethodField()
fields = ('name', 'contact', 'permission_reminder',
'campaign_defaults', 'email_type_option')
How do I create the contact JSON list with the address etc in it?
What you want is a DictField not a ListField, the key contact in your desired JSON output is an object (dict in Python), not a list:
contact = serializers.DictField(
address1=serializers.CharField(source='address_line1'),
address2=serializers.CharField(source='address_line2'),
...
)
Here's another way that is more manual:
class MySerializer(serializers.ModelSerializer):
contact = serializers.SerializerMethodField()
def get_contact(self, obj):
return dict(
address1=obj.address1, # As long as the fields are auto serializable to JSON
some_field=SomeSerializer(obj.some_field).data,
)

Categories

Resources