I am trying out an implementation. Although I have figured the logic out, I am having issues representing it programatically. I need your help or guidance.
Below is the detailed explanation of my code and what i am trying to achieve, please pardon me as it would be a long read.
What I want to achieve
I want to create an endpoint - /order/tradeadvisor/{{producer_order_id}}, so that if the endpoint is hit, then it should first record the producer_order_id in a variable, then it should go to the Order model and loop through it fetching all order_id, user_id with the user_type=1.
After that it should, now produce a a single record where, the user caprice is equal to producer floorprice(where the producer is the logged in user) and then the user needed engery is equal to the producers surplus and then store this record in the Trade table.
What i have done
User.model:
class User(AbstractBaseUser, PermissionsMixin):
dso = models.ForeignKey(to=Dso,related_name='dso',null=True,on_delete=models.CASCADE)
name = models.CharField(max_length=70)
address = models.CharField(max_length=70)
roleId = models.IntegerField(default=1)
customerId = models.CharField(max_length=70, blank=False, default='')
floorPrice = models.DecimalField(max_digits=10, max_length=255, decimal_places=2, null=True)
capPrice = models.DecimalField(max_digits=10, max_length=255, decimal_places=2, null=True)
tradeStrategy = models.CharField(max_length=255, null=True)
username=models.CharField(max_length=255, unique=True, db_index=True)
email=models.EmailField(max_length=255, unique=True, db_index=True)
is_verified = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_trading = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
created_at=models.DateTimeField(auto_now_add=True)
updated_at=models.DateTimeField(auto_now=True)
User serializer:
class UserSerializer(serializers.ModelSerializer):
energy_data = EnergyDataSerializer(read_only=True)
dso = DsoSerializer(read_only = True)
class Meta:
model = User
fields = ('id',
'name',
'email',
'address',
'roleId',
'is_active',
'customerId',
'dso',
'floorPrice',
'capPrice',
'tradeStrategy',
'username',
'is_verified',
'is_staff',
'is_trading',
'created_at',
'updated_at',
'energy_data', //this is a nested dictionary holding data of the energySurplus and energyNeeded
)
depth = 1
Trade Serializer:
class TradeSerializer(serializers.ModelSerializer):
consumer_id = serializers.PrimaryKeyRelatedField(allow_null=False, queryset=User.objects.all())
producer_id = serializers.PrimaryKeyRelatedField(allow_null=False, queryset=User.objects.all())
c_order_id = serializers.PrimaryKeyRelatedField(allow_null=False, queryset=Order.objects.all())
p_order_id = serializers.PrimaryKeyRelatedField(allow_null=False, queryset=Order.objects.all())
startTime = serializers.DateTimeField()
class Meta:
model = Trade
fields = ('id',
'startTime',
'stopTime',
'price',
'c_order_id',
'p_order_id',
'consumer_id',
'producer_id',
'producer_location',
'consumer_location',
'energyQuantity',
)
Order Serializer
class OrderSerializer(serializers.ModelSerializer):
trades = TradeSerializer(read_only=True, many= True)
user_id = serializers.PrimaryKeyRelatedField(allow_null=False, queryset=User.objects.all())
user_type = serializers.IntegerField()
created_at = serializers.DateTimeField()
class Meta:
model = Order
fields = ('id',
'user_id',
'user_type',
'trades',
'created_at',
)
depth = 1
Views.py:
class TradeAdvisor(views.APIView):
serializer_class = TradeSerializer
permission_classes = (permissions.IsAuthenticated,)
def get(self, request, *args, **kwargs):
user = self.request.user
producer_order_id = self.kwargs['p_order_id']
orders = Order.objects.filter(user_type=1)
for order in orders:
consumer = order.user_id
if consumer['user_id']['is_trading']:
if ((consumer['capPrice'] == user.floorPrice ) and (consumer['energy_data']['energyNeeded'] == user.energy_data['energySurplus'])):
date_time = datetime.datetime.now()
data ={
"startTime": date_time,
"stopTime": "",
"price": user.flooPrice,
"c_order_id": order.id,
"p_order_id": producer_order_id,
"consumer_id": consumer,
"producer_id": user,
"producer_location": user.address,
"consumer_location": consumer['address'],
"energyQuantity": user.energy_data['energySurplus']
}
serializer = self.serializer_class(data=data)
serializer.save()
else:
return Response({'error': 'No active consumers'}, status = status.HTTP_400_BAD_REQUEST)
else:
return Response({'error': 'No active consumers'}, status = status.HTTP_400_BAD_REQUEST)
So this is what i have tried, i am pretty sure is wrong and also i do get an error
'int'(consumer['user_id']['is_trading']) object is not subscriptable
Just use consumer as a User instance, i.e:
if consumer.is_trading:
# instead of
if consumer['user_id']['is_trading']
and later you want to check Order, not User. It's not about Django knowledge, everything here is almost pure pythonish.
PS. please don't set ForeignKey field with _id. It's very misleading for other developers. I've just lost 5 minutes because I didn't realise that.
Related
I am trying to post multiple data into my DataBase Using Django Rest framework (DRF).
AttributeError at /apiv2/api/processorder/order/
Got AttributeError when attempting to get a value for field subcategory on serializer MyProcessOrderSerializer.
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 'subcategory'.
models.py
class SubCategory(models.Model):
category = models.ForeignKey(Category, related_name='subcategory', on_delete=models.CASCADE)
name = models.CharField("Food Name", max_length=50, help_text="Name of The Food")
price = models.DecimalField("Food Price", max_digits=5, decimal_places=2)
quantity = models.PositiveIntegerField("Qty.", help_text="Quantity of the food Item you want")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return f'{self.name}'
class Meta:
verbose_name = 'SubCategory'
verbose_name_plural = 'SubCategories'
class Order(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
bike = models.ForeignKey(User, related_name='bike', on_delete=models.CASCADE, blank=True, null=True)
package = models.ForeignKey(PackageType, related_name='package', on_delete=models.CASCADE, blank=True, null=True)
total_price = models.DecimalField(max_digits=10, decimal_places=2, default=0000.0)
qty = models.PositiveIntegerField(default=1)
shipping_address = models.CharField("Delivery Address", max_length=150)
paid = models.BooleanField(default=False)
ordernote = models.TextField("Order Notes", null=True)
shipped = models.BooleanField(default=False)
complete = models.BooleanField(default=False)
received = models.BooleanField(default=False)
refund_requested = models.BooleanField(default=False)
refund_granted = models.BooleanField(default=False)
ref_code = models.CharField(max_length=20, blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ('-created_at',)
def __str__(self):
return '{}'.format(self.id)
def order(self):
if not hasattr(self, '_order'):
self._order = self.order.all()
return self._order
'''
def get_total_cost(self):
total_cost = sum(orders.get_cost() for orders in self.order.all())
return total_cost
'''
class ProcessOrder(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
order = models.ForeignKey(Order, related_name='order', on_delete=models.CASCADE)
quantity = models.PositiveIntegerField("Qty.", default=1, help_text="Quantity of the food Item you want")
#category = models.ForeignKey(Category, related_name='category', on_delete=models.CASCADE)
subcategory = models.ForeignKey(SubCategory, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return f'{self.order} -- {self.subcategory.name}'
serializers.py
class MyProcessOrderSerializer(serializers.ModelSerializer):
#subcategory_name = serializers.RelatedField(source='subcategory.id', read_only=True)
#subcategory_set = SubCategoryOrderSerializer(many=True)
class Meta:
model = ProcessOrder
fields = ('quantity', 'subcategory', 'user')
read_only_fields = ('user', )
def create(self, validated_data):
return ProcessOrder.objects.create(**validated_data)
view.pf
#api_view(['POST'])
#permission_classes([IsAuthenticated])
def processorder_view(request):
orderuser = User.objects.get(id=request.user.id)
serializer = MyProcessOrderSerializer(data=request.data, many=True)
if serializer.is_valid():
order = Order.objects.create(user=orderuser, ref_code=create_ref_code())
order.save()
processorder = serializer.save(order=order, user=orderuser)
return Response(MyProcessOrderSerializer(processorder).data, status=status.HTTP_201_CREATED)
else: #return Response("Process Order Created Successfully")
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
I am now trying to make a POST such as this but getting the above error.
[{
"quantity": 16,
"subcategory": 1
},
{
"quantity": 14,
"subcategory": 3
}
]
You have to explicitly specify the relation in the serializer either with one of the built-in serializer:
Serializer relations
class MyProcessOrderSerializer(serializers.ModelSerializer):
# StringRelatedField and PrimaryKeyRelatedField are some of the built in ones.
subcategory = serializers.StringRelatedField(source='subcategory.id', read_only=True)
user = serializer.PrimaryKeyRelatedField()
class Meta:
model = ProcessOrder
fields = ('quantity', 'subcategory', 'user')
read_only_fields = ('user', )
def create(self, validated_data):
# If you want to accect new subcategory object via the endpoint you need further action here, see the docs.
return ProcessOrder.objects.create(**validated_data)
or by creating a custom subcategory serializer and then in serializer:
class UserSerializer(serializers.ModelSerializer):
class Meta:
fields = ('id', 'email', 'password', 'first_name', 'last_name')
class SubCategorySerializer(serializers.ModelSerializer):
class Meta:
fields = # whatever fields youd'e like to include
class MyProcessOrderSerializer(serializers.ModelSerializer):
# StringRelatedField is One of the built in ones.
sybcategory = SubCategorySerializer()
user = UserSerializer()
class Meta:
model = ProcessOrder
fields = ('quantity', 'subcategory', 'user')
read_only_fields = ('user', )
def create(self, validated_data):
# If you want to accect new subcategory object via the endpoint you need further action here, see the docs.
return ProcessOrder.objects.create(**validated_data)
And, I noticed you have Foreign Key to User in process order and order itself,
You could delete the user field from the process order and access it via the order relation, for that you can specify the user field in the subcategory serializer and the subcategory serializer in the process order serializer as I showed above.
And if I understand the purpose of creating a process order model, the relation should be a One to One and not Foreign key, But maybe I'm not seeing the whole picture here.
I think the problem apear in request.data in this line :
serializer = MyProcessOrderSerializer(data=request.data, many=True)
You should loop throught your object list and pass just the object not the whole list .
exemple :
{ "list_":[{"quantity": 7 ,"subcategory": 3}, {"quantity": 7 ,"subcategory": 3}] }
To get the first object from the request :
request.data.get('list_')[0]
I was able to solve the problem with this code both in my views and serialize
views.py
#api_view(['POST'])
#permission_classes([IsAuthenticated])
def processorder_view(request):
orderuser = User.objects.get(id=request.user.id)
data = request.data
order = Order.objects.create(user=orderuser, ref_code=create_ref_code())
if isinstance(data, list):
serializer = MyProcessOrderSerializer(data=request.data, many=True)
else:
serializer = MyProcessOrderSerializer(data=request.data)
if serializer.is_valid():
processorder = serializer.save(order=order, user=request.user)
return Response(status=status.HTTP_201_CREATED)
#return HttpResponse("Question created", status=201)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializers.py
class MyProcessOrderSerializer(serializers.ModelSerializer):
#subcategory_name = serializers.RelatedField(source='subcategory.id', read_only=True)
#subcategory_set = SubCategoryOrderSerializer(many=True)
#subcategory = serializers.StringRelatedField(source='subcategory.id', read_only=True)
class Meta:
model = ProcessOrder
fields = ('quantity', 'subcategory', 'user')
read_only_fields = ('user', )
def create(self, validated_data):
return ProcessOrder.objects.create(**validated_data)
Then, I was able to send multiple data with this sample.
[
{
"subcategory": 1,
"quantity": 12
},
{
"subcategory": 3,
"quantity": 12
}
]
I was trying to add new relation to many to many records,
for example i have these models:
models.py
class Team(models.Model):
name = models.CharField(blank=True, unique=True, max_length=100)
players = models.ManyToManyField(User, blank=True, related_name='players')
class TeamInvite(models.Model):
from_user = models.ForeignKey(User, on_delete=models.DO_NOTHING, related_name='invite_by', blank=True, null=True)
to_user = models.ForeignKey(User, on_delete=models.DO_NOTHING, related_name='invite_to', blank=True, null=True)
team = models.ForeignKey(Team, on_delete=models.CASCADE, related_name='invite_to_team', blank=True, null=True)
status = models.NullBooleanField(blank=True, null=True, default=None,)
and my serializer:
serializers.py
class TeamInviteCreateSerializer(serializers.ModelSerializer):
team = serializers.PrimaryKeyRelatedField(queryset=Team.objects.all())
from_user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all())
class Meta:
model = TeamInvite
fields = ('id', 'from_user', 'to_user', 'team', 'status')
after that the user which in to_user will take an action to TeamInvite like accept or decline.
I need the serializer which will take the new user and add him to the existing team like the following serializer:
class TeamInviteAcceptDeclineSerializer(serializers.ModelSerializer):
method_name = serializers.SerializerMethodField()
class Meta:
model = TeamInvite
fields = ('id', 'from_user', 'date_time', 'team', 'method_name', 'status')
def get_method_name(self, *args, **kwargs):
method_name = None # kwargs['context']['request'].method_name
return method_name
def update(self, instance, validated_data):
instance.team = validated_data.get('team', instance.team)
method_name = validated_data.get('method_name')
instance.status = validated_data.get('status', instance.status)
instance.to_user = validated_data.get('to_user', instance.to_user)
if method_name == 'decline':
instance.status = False
else:
instance.status = True
team = Team.objects.get(pk=instance.team.pk)
team.players.add(instance.to_user)
# team.players.create(team_id=team, user_id=instance.to_user)
team.save()
instance.save()
return instance
update function does not add the user to existing team and doesn't raise any error either. What am i missing here?
my request was:
{
"from_user": 1,
"to_user": 23
"team": 64,
"method_name": "accept",
"status": null
}
thank you
I got the missing point in my code..
it was in:
class TeamInviteAcceptDeclineSerializer(serializers.ModelSerializer):
method_name = serializers.SerializerMethodField()
class Meta:
model = TeamInvite
fields = ('id', 'from_user', 'date_time', 'team', 'method_name', 'status')
fields = missed 'to_user' pram
I have a model named tranasaction.
class transactions(models.Model):
id = models.AutoField(primary_key=True)
date = models.DateTimeField(default=datetime.now, blank=True)
saleduser = models.ForeignKey('UserData',on_delete=models.CASCADE, related_name='vclouduser_data', blank=True, null=True)
brand = models.CharField(max_length=50,blank=True)
type = models.CharField(max_length=50,blank=True)
quantity = models.DecimalField(blank=True,null=True,max_digits=20,decimal_places=2)
amount = models.DecimalField(blank=True,null=True,max_digits=20,decimal_places=2)
And I need to create a summary report,
so I create a new Model.
class SaleSummary(transactions):
class Meta:
proxy = True
verbose_name = 'Sale Summary'
verbose_name_plural = 'Sales Summary'
what i need that i need to get the total amount of each type as a new model.
please help me to solve this.
Thanks in advance.
Here is an example of a proxy model for a normal model, with a filtering example. I hope it will be helpful for you that how can you create the proxy model and how can you filter specific data from any model for the admin site. You also can apply this for your custom API response, Then you should write this code in serializers. Best of luck.
models.py
class UserModel(AbstractBaseUser):
"""
Purpose: create a custom auth user table
"""
name = models.CharField('name of user',max_length=256)
email = models.EmailField('email address', unique=True)
date_joined = models.DateTimeField('user creation date', auto_now_add=True)
is_admin = models.BooleanField('is a admin', default=False)
is_staff = models.BooleanField('is a staff', default=False)
is_superuser = models.BooleanField('if a superuser', default=False)
status = models.ForeignKey(SesameUserStatus, on_delete = models.CASCADE, related_name='sesame_user_status_type', default=2)
organization = models.ForeignKey(Organization, on_delete = models.CASCADE, related_name='sesame_user_organization_info', default=1)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name']
def has_perm(self,prm,obj=None):
return self.is_active and self.is_admin
def has_module_perms(self,app_level):
return self.is_active and self.is_admin
def __str__(self):
return f'{self.name} // {self.email} // {self.organization.name}'
class Meta:
verbose_name = "User"
verbose_name_plural = "Users"
indexes = [
models.Index(fields=['email']),
]
class UserProxyModel(UserModel):
"""
Purpose: create proxy model to visualize only pending user
"""
class Meta:
proxy = True
verbose_name = "Pending User"
verbose_name_plural = "Pending Users"
###########################################################################
admin.py
class UserAdmin(admin.ModelAdmin):
list_display = ['id', 'name', 'email', 'date_joined', 'is_admin', 'is_staff']
class Meta:
model = UserModel
class UserProxyModelAdmin(admin.ModelAdmin):
list_display = ['id', 'name', 'email', 'date_joined', 'is_admin', 'is_staff', 'organization', 'status']
def get_queryset(self, request):
qs = super().get_queryset(request)
if request.user.is_superuser:
return qs.filter(status=SESAME_USERS["status"]["PENDING"]).order_by('id')
return None
class Meta:
model = UserProxyModel
admin.site.register(UserModel, UserAdmin)
admin.site.register(UserProxyModel, UserProxyModelAdmin)
I am using Django 1.10.5 and djangorestframework 3.5.3.
I have 2 models that are related with one to many relation:
class Minisymposium(models.Model):
STATUS_CHOICES = (
('pending', 'Pending'),
('approved', 'Approved'),
('denied', 'Denied'))
id = models.AutoField(primary_key=True)
number = models.IntegerField(default=0, null=False)
title = models.CharField(max_length=100, null=False)
description = models.TextField(max_length=9000, null=False)
status = models.CharField(max_length=100, choices=STATUS_CHOICES, null=False, default='pending')
user = models.ForeignKey(User, null=False, related_name='user')
corresponding_organizer = models.ForeignKey(User, null=False, related_name='corresponding_organizer')
anticipated_abstracts = models.IntegerField(null=False)
anticipated_attendees = models.IntegerField(null=False)
date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '{0}-{1}'.format(self.number, self.title)
class UnregisteredOrganizer(models.Model):
id = models.AutoField(primary_key=True)
first_name = models.CharField(max_length=1000, blank=False)
last_name = models.CharField(max_length=1000, blank=False)
email = models.EmailField(max_length=254, blank=True)
affiliation = models.CharField(max_length=254, help_text='(institution only)', blank=True)
phone_number = PhoneNumberField(blank=True)
minisymposium = models.ForeignKey(Minisymposium, related_name='other_organizers')
Each model have a serializer. But the problem is with Minisymposium`s serializer. Because I want to send an UnregisteredOrganizer`s ID on creating one, and get the whole object as serialized on getting a Minisymposium.
And as I see in ModelSerializer it is not possible:
class MinisymposiumSerializer(serializers.ModelSerializer):
other_organizers = UnregisteredOrganizerSerializer(many=True)
class Meta:
model = Minisymposium
fields = ('url', 'id', 'number', 'title', 'description', 'status', 'user', 'corresponding_organizer',
'anticipated_abstracts', 'anticipated_attendees', 'other_organizers', 'date')
def create(self, validated_data):
other_organizers = []
if 'other_organizers' in validated_data:
other_organizers = validated_data.pop('other_organizers')
minisymposium = Minisymposium.objects.create(**validated_data)
minisymposium.save()
for organizer in other_organizers:
UnregisteredOrganizer.objects.create(minisymposium=minisymposium, **organizer).save()
return minisymposium
How can I do that?
Thank you !
Because I want to send an UnregisteredOrganizer`s ID on creating one, and get the whole object as serialized on getting a Minisymposium.
Why have such an inconsistent API ?
The recommended option here is to set the fields on Minisymposium as read_only except for the id which should be read_only=False.
Therefore, you can get the full object when getting the data and just expect the id when post/put/patching the data. Posted JSON would look like:
{
...
"url": "whatever",
"title": "Some nice title",
"other_organizers": [{"id": 5}, {"id": 5123}]
}
Creation code would be like:
def create(self, validated_data):
other_organizers = validated_data.pop('other_organizers', [])
minisymposium = Minisymposium.objects.create(**validated_data)
minisymposium.save()
organizers = []
for organizer_id in other_organizers:
organizers .append(UnregisteredOrganizer.objects.get(id=organizer_id)
minisymposium. other_organizers = organizers
return minisymposium
I looked for an answer to this question specifically for Django Rest, but I haven't found one anywhere, although I think a lot of people have this issue. I'm trying to create an object with multiple nested relationships but something is keeping this from happening. Here are my models for reference:
class UserProfile(models.Model):
user = models.OneToOneField(User, unique=True, null=True)
tmp_password = models.CharField(max_length=32)
photo = models.ImageField(upload_to='media/', blank=True, null=True)
likes = models.IntegerField(blank=True, null=True)
dislikes = models.IntegerField(blank=True, null=True)
def __unicode__(self):
return unicode(self.user.username)
class Item(models.Model):
"""Item Object Class"""
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=125, blank=True)
price = models.FloatField(default=0, blank=True)
rating = models.IntegerField(default=0, blank=True)
description = models.TextField(max_length=300, blank=True)
photo = models.ImageField(upload_to="media/", blank=True)
barcode = models.CharField(max_length=20, blank=True)
photo_url = models.URLField(max_length=200, blank=True)
item_url = models.URLField(max_length=200, blank=True)
def __unicode__(self):
return unicode(self.name)
class Favorite(models.Model):
user = models.OneToOneField(User, null=True)
items = models.ManyToManyField(Item)
def __unicode__(self):
return unicode(self.user.username)
def admin_names(self):
return '\n'.join([a.name for a in self.items.all()])
And here are my serializers:
class ItemSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Item
fields = ('id', 'name', 'price', 'description', 'rating', 'photo', 'barcode', 'photo_url','item_url' )
class FavoriteSerializer(serializers.ModelSerializer):
class Meta:
model = Favorite
exclude = ('id', 'user')
class UserProfileSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = UserProfile
fields = ('likes', 'dislikes', 'photo', 'tmp_password')
class UserSerializer(serializers.HyperlinkedModelSerializer):
userprofile = UserProfileSerializer()
favorite = FavoriteSerializer()
class Meta:
model = User
fields = (
'id', 'username', 'url',
'email', 'is_staff', 'password',
'userprofile', 'favorite'
)
def create(self, validated_data):
profile_data = validated_data.pop('userprofile')
favorites_data = validated_data.pop('favorite')
user = User.objects.create_user(**validated_data)
user_profile = UserProfile.objects.create(user=user, **profile_data)
favorite = Favorite(user=user)
favorite.save()
print favorite.items
for item in favorites_data:
favorite.items.add(item)
print favorite.items
return user
What I am having trouble with is the create() method on UserSerializer. What's happening is I can't .add() the data from favorites_data to the favorite object. I get an error saying invalid literal for int() with base 10: 'items'. I guess this makes sense, but if I try this instead of using the for loop:
favorite.items.add(**favorites_data)
I just get an error saying add() got an unexpected keyword argument 'items'. Finally, If I try this:
favorite.items.add(favorites_data)
I just get this error: unhashable type: 'OrderedDict'
What am I doing wrong in this approach? Obviously, favorites_data exist, but I'm not inserting it properly. Thanks for any help!
I think favorite.items.add expects you to pass in a single instance of an Item, so you should replace this:
for item in favorites_data:
favorite.items.add(item)
With this:
for key in favorites_data:
for item in favorites_data[key]:
favorite.items.add(item)