creating order from orderitem drf - django

i am trying to create order from orderitem. problem is how can i pass orderitem object to order.item field:
models.py:
class OrderItem(models.Model):
image_number = models.CharField(max_length=20)
title = models.CharField(max_length=20)
image_size = models.CharField(max_length=50)
file_type = models.CharField(max_length=20)
price = models.CharField(max_length=50)
def __str__(self):
return self.title
class Order(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, blank=True,null=True)
items = models.ManyToManyField(OrderItem)
start_date = models.DateTimeField(auto_now_add=True)
ordered_date = models.DateField(auto_now_add=False,blank=True,null=True)
ordered = models.BooleanField(default=False)
def __str__(self):
return str(self.user)
serializers.py:
class AddtocartSerializers(serializers.ModelSerializer):
class Meta:
model = OrderItem
fields = ['image_number','title','image_size','file_type','price']
class CartSerializer(serializers.ModelSerializer):
user = serializers.PrimaryKeyRelatedField(queryset=CustomUser.objects.all())
items = serializers.ListField(child=serializers.PrimaryKeyRelatedField(queryset=OrderItem.objects.all(), required=True), required=True)
ordered_date = serializers.DateField()
class Meta:
model = Order
fields = ['user', 'items', 'ordered_date']
views.py:
class AddtocartView(generics.CreateAPIView):
authentication_classes = []
permission_classes = [IsAuthenticated]
pagination_class = None
queryset = OrderItem.objects.all()
serializer_class = AddtocartSerializers
def perform_create(self, serializer):
new_order_item = serializer.save()
user=CustomUser.objects.filter(id=self.request.user.id).first()
new_order = Order.objects.create(user=user)
new_order.items.add(new_order_item)
def __str__(self):
return self.user
class CartView(generics.ListAPIView):
authentication_classes = []
permission_classes = []
pagination_class = None
queryset=Order.objects.all()
serializer_class = CartSerializer
urls.py:
path('addtocart/',views.AddtocartView.as_view(),name='addtocart'),
path('cart/',views.CartView.as_view(),name='cart'),
customuser model:
class CustomUser(AbstractBaseUser, PermissionsMixin):
USER_TYPE_CHOICES = (
('user','user'),
('freelance_photographer', 'freelance_photographer'),
('photographer', 'photographer'),
('client', 'client'),
)
user_type = models.CharField(choices=USER_TYPE_CHOICES, null=True,max_length=20)
email = models.EmailField(max_length = 100, unique = True)
first_name = models.CharField(max_length = 100, null = True, blank = True)
last_name = models.CharField(max_length = 100, null = True, blank = True)
is_staff = models.BooleanField(default = False)
is_superuser = models.BooleanField(default = False)
is_active = models.BooleanField(default = True)
last_login = models.DateTimeField(null = True, blank = True)
date_joined = models.DateTimeField(auto_now_add=True)
USERNAME_FIELD = "email"
EMAIL_FIELD = "email"
REQUIRED_FIELD = []
objects = UserManager()
def get_absolute_url(self):
return "/users/%i/" % (self.pk)
error:
Direct assignment to the forward side of a many-to-many set is prohibited. Use items.set() instead.
Is there any better way to create order?

You can create order with order item this way:
class AddtocartView(generics.CreateAPIView):
authentication_classes = []
permission_classes = [IsAuthenticated]
pagination_class = None
queryset = OrderItem.objects.all()
serializer_class = AddtocartSerializers
def perform_create(self, serializer):
new_order_item = serializer.save()
new_order = Order.objects.create()
new_order.items.add(new_order_item)

Related

How can I show the StringRelatedField instead of the Primary Key while still being able to write-to that field using Django Rest Framework?

Models:
class CrewMember(models.Model):
DEPARTMENT_CHOICES = [
("deck", "Deck"),
("engineering", "Engineering"),
("interior", "Interior")
]
first_name = models.CharField(max_length=25)
last_name = models.CharField(max_length=25)
email = models.EmailField()
department = models.CharField(max_length=12, choices=DEPARTMENT_CHOICES)
date_of_birth = models.DateField()
join_date = models.DateField()
return_date = models.DateField(null=True, blank=True)
leave_date = models.DateField(null=True, blank=True)
avatar = models.ImageField(null=True, blank=True)
active = models.BooleanField(default=True)
def __str__(self):
return f"{self.first_name} {self.last_name}"
class RosterInstance(models.Model):
date = models.DateField(default=timezone.now)
deckhand_watchkeeper = models.ForeignKey(CrewMember, on_delete=models.PROTECT, null=True, related_name="deckhand_watches")
night_watchkeeper = models.ForeignKey(CrewMember, on_delete=models.PROTECT, null=True, related_name="night_watches")
def __str__(self):
return self.date.strftime("%d %b, %Y")
Views:
class CrewMemberViewSet(viewsets.ModelViewSet):
queryset = CrewMember.objects.all()
serializer_class = CrewMemberSerializer
filter_backends = [SearchFilter]
search_fields = ["department"]
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
instance.active = False
instance.save()
return Response(status=status.HTTP_204_NO_CONTENT)
class RosterInstanceViewSet(viewsets.ModelViewSet):
queryset = RosterInstance.objects.all()
serializer_class = RosterInstanceSerializer
Serializers:
class CrewMemberSerializer(serializers.ModelSerializer):
class Meta:
model = CrewMember
fields = "__all__"
class RosterInstanceSerializer(serializers.ModelSerializer):
class Meta:
model = RosterInstance
fields = "__all__"
The resulting data looks like this:
{
"id": 2,
"date": "2020-12-09",
"deckhand_watchkeeper": 1,
"night_watchkeeper": 3
}
But I want it to look like this:
{
"id": 2,
"date": "2020-12-09",
"deckhand_watchkeeper": "Joe Soap",
"night_watchkeeper": "John Smith"
}
I can achieve the above output by using StringRelatedField in the RosterInstanceSerializer but then I can no longer add more instances to the RosterInstance model (I believe that is because StringRelatedField is read-only).
Because StringRelaredField is always read_only, you can use SlugRelatedField instead:
class RosterInstanceSerializer(serializers.ModelSerializer):
deckhand_watchkeeper = serializers.SlugRelatedField(
slug_field='deckhand_watchkeeper'
)
night_watchkeeper = serializers.SlugRelatedField(
slug_field='night_watchkeeper'
)
class Meta:
model = RosterInstance
fields = ['id', 'date', 'deckhand_watchkeeper', 'night_watchkeeper']
I was created a WritableStringRelatedField to do that.
class WritableStringRelatedField(serializers.SlugRelatedField):
def __init__(self, display_field=None, *args, **kwargs):
self.display_field = display_field
# Set what attribute to be represented.
# If `None`, use `Model.__str__()` .
super().__init__(*args, **kwargs)
def to_representation(self, obj):
# This function controls how to representation field.
if self.display_field:
return getattr(obj, self.display_field)
return str(obj)
def slug_representation(self, obj):
# It will be called by `get_choices()`.
return getattr(obj, self.slug_field)
def get_choices(self, cutoff=None):
queryset = self.get_queryset()
if queryset is None:
# Ensure that field.choices returns something sensible
# even when accessed with a read-only field.
return {}
if cutoff is not None:
queryset = queryset[:cutoff]
return OrderedDict([
(
self.slug_representation(item),
# Only this line has been overridden,
# the others are the same as `super().get_choices()`.
self.display_value(item)
)
for item in queryset
])
Serializers:
class RosterInstanceSerializer(serializers.ModelSerializer):
deckhand_watchkeeper = WritableStringRelatedField(
queryset=CrewMember.objects.all(),
slug_field='id',
label='Deckhand Watchkeeper',
)
night_watchkeeper = WritableStringRelatedField(
queryset=CrewMember.objects.all(),
slug_field='id',
label='Night Watchkeeper',
)
class Meta:
model = RosterInstance
fields = "__all__"

Django / Customized ModelChoiceField: how label_from_instance works?

I use ModelChoiceField with initial value just for display (readonly field).
But value displayed is model id and I want to display customized value that will be a concatenation of 3 fields. I've override ____str____ method but it is not applyed.
I try to make customize ModelChoiceFiedl to define label_from_instance that seems to be the way to do what I want but it is not applyed...
models.py
class Utilisateur(SafeDeleteModel):
_safedelete_policy = SOFT_DELETE_CASCADE
uti_ide = models.AutoField(primary_key = True)
# pro_ide = models.ForeignKey(Projet, on_delete = models.CASCADE) # related project
projets = models.ManyToManyField(Projet, through='UtilisateurProjet')
uti_nom = models.CharField("Nom", max_length=20)
uti_pre = models.CharField("Prénom", max_length=20)
uti_mai = models.CharField("Email", max_length=40)
uti_sit = models.CharField("Equipe", max_length=20, null=True, blank=True)
uti_pro = models.CharField("Fonction/profil", max_length=200, null=True, blank=True)
uti_log = models.CharField("Log utilisateur", max_length=20, null=True, blank=True)
uti_dat = models.DateTimeField("Date log",auto_now_add=True, null=True, blank=True)
log = HistoricalRecords()
#classmethod
def options_list(cls,pro_ide):
# projet = Projet.objects.get(pro_ide=pro_ide)
# utilisateurs = Utilisateur.objects.filter(pro_ide=projet.pro_ide)
utilisateurs = Utilisateur.objects.filter(projets__pro_ide=pro_ide)
the_opts_list = [(utilisateur.uti_ide, utilisateur.uti_nom+', '+utilisateur.uti_pre) for utilisateur in utilisateurs]
the_opts_list.insert(0, (None, ''))
return the_opts_list
class Meta:
db_table = 'tbl_uti'
verbose_name_plural = 'Utilisateurs'
ordering = ['uti_ide']
def __str__(self):
return f"{self.uti_nom}, {self.uti_pre} ({self.uti_mai})"
forms.py
class UtilisateurModelChoiceField(ModelChoiceField):
def label_from_instance(self, obj):
print('label')
return obj.uti_nom+', '+obj.uti_pre+' ('+obj.uti_mai+')'
class UtilisateurProjetUpdateForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop("request")
super(UtilisateurProjetUpdateForm, self).__init__(*args, **kwargs)
# print('kwargs',self.request)
# print('projet',self.request['projet'])
# print('utilisateur',self.request['utilisateur'])
PROJETS = Projet.objects.all()
UTILISATEURS = Utilisateur.objects.all()
self.fields["pro_ide"] = forms.ModelChoiceField(queryset = PROJETS, label = "Nom projet", widget = forms.HiddenInput(), initial = Projet.objects.get(pro_ide=self.request['projet']))
self.fields["uti_ide"] = UtilisateurModelChoiceField(queryset = UTILISATEURS, label = "Nom, prénom de l'utilisateur", widget = forms.TextInput(attrs={'readonly':'readonly'}), initial = Utilisateur.objects.get(uti_ide=self.request['utilisateur']),) #,to_field_name="uti_nom"
class Meta:
model = UtilisateurProjet
fields = ('pro_ide','uti_ide',)
in forms.py under that last class Meta: you need to add:
field_classes = {
'pro_ide': UtilisateurModelChoiceField,
'uti_ide': UtilisateurModelChoiceField,
}

pass username from token to save username in model

This is my model file which has the owner field name
class PotholeImages(models.Model):
"""Upload images with details """
image = models.ImageField(
upload_to='photos/%Y/%m/%d',
)
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
default = 'unknown',
)
state_name = models.CharField(
blank = False,
max_length = 30,
default = 'unknown',
)
country_name = models.CharField(
blank = False,
max_length = 30,
default = 'unknown',
)
name = models.CharField(default=uuid.uuid4, max_length=40)
cordinate_X = models.DecimalField(max_digits=22, decimal_places=16)
cordinate_Y = models.DecimalField(max_digits=22, decimal_places=16)
created_date = models.DateTimeField(auto_now_add=True)
road_name = models.CharField(max_length = 100, default = 'unknown')
def __str__(self):
return self.name
Serializer file
class ImageSerializer(serializers.ModelSerializer):
"""Uploading Pothoele Images"""
class Meta:
model = PotholeImages
fields = ('image','state_name',
'country_name','cordinate_X',
'cordinate_Y','road_name',)
def to_representation(self, instance):
rep = super(ImageSerializer, self).to_representation(instance)
rep['owner'] = instance.owner.username
# print(rep)
return rep
views file
class ImageViewSet(viewsets.ModelViewSet):
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAuthenticated,)
queryset = PotholeImages.objects.all()
serializer_class = serializers.ImageSerializer
def perform_create(self, serializer):
print(self.request.user)
serializer.save(user=self.request.user)
I want whenever a person sends a post request on
http://127.0.0.1:8000/images_api/imageView/
Then from the token, username gets detected and it should be passed in the owner field name.
Could anyone please help
Thanks
Finally, I have found the answer I have made through APIView
class ImageAPIView(APIView):
authentication_classes = (TokenAuthentication,)
def post(self, request):
## username
user = request.user
is_tokened = Token.objects.filter(user = user)
print("user name is ", user)
data = request.data
data['owner'] = user.id
serializer = serializers.ImageSerializer(data=data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=200)
ResponseData = "{} image sent by user".format(user.id)
return Response(ResponseData, status=status.HTTP_200_OK)

How to add to cart in DRF

I am trying to create order:
models.py:
class OrderItem(models.Model):
image_number = models.CharField(max_length=20)
title = models.CharField(max_length=20)
image_size = models.CharField(max_length=50)
file_type = models.CharField(max_length=20)
price = models.CharField(max_length=50)
def __str__(self):
return self.title
class Order(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
items = models.ManyToManyField(OrderItem)
start_date = models.DateTimeField(auto_now_add=True)
ordered_date = models.DateTimeField()
ordered = models.BooleanField(default=False)
def __str__(self):
return str(self.user)
serializers.py:
class AddtocartSerializers(serializers.ModelSerializer):
class Meta:
model = OrderItem
fields = ['image_number','title','image_size','file_type','price']
class CartSerializers(serializers.ModelSerializer):
class Meta:
model = Order
fields = ['item',
'start_date',
'ordered_date'
]
views.py:
class AddtocartView(viewsets.ModelViewSet):
authentication_classes = []
permission_classes = []
pagination_class = None
queryset=OrderItem
serializer_class = AddtocartSerializers
class CartView(viewsets.ModelViewSet):
authentication_classes = []
permission_classes = []
pagination_class = None
queryset=Order.objects.all()
serializer_class = CartSerializers
urls.py: api endpint
path('addtocart/',views.AddtocartView.as_view({'get':'list'}),name='addtocart'),
path('cart/',views.CartView.as_view({'get':'list'}),name='cart'),
I am confused here; should I create new order objects from serialzers or views?
You should override the created method on the AddtocartSerializers to add the order item to the order.
You can see more information about it here: https://www.django-rest-framework.org/api-guide/serializers/#writing-create-methods-for-nested-representations

Django DRF - Include Foreign-Key field to serializer

How do I add 'platform_description' field to be part of battlesSerializer result?
Model
class battles(models.Model):
# Fields
created = models.DateTimeField(auto_now_add=True, editable=False)
last_updated = models.DateTimeField(auto_now=True, editable=False)
wager = models.FloatField(max_length=30)
battle_rules = models.CharField(max_length=30,null = True,blank = True)
accepting_time = models.DateTimeField()
offer_expiration_time = models.DateTimeField(null = True,blank = True)
battle_time = models.DateTimeField(null = True,blank = True)
rake = models.FloatField()
# Relationship Fields
platform_id = models.ForeignKey('platforms.game_platforms', related_name='seal')
class Meta:
ordering = ('-created',)
def __unicode__(self):
return u'%s' % self.id
def get_absolute_url(self):
return reverse('platforms_battles_detail', args=(self.id,))
def get_update_url(self):
return reverse('platforms_battles_update', args=(self.id,))
class game_platforms(models.Model):
# Fields
created = models.DateTimeField(auto_now_add=True, editable=False)
last_updated = models.DateTimeField(auto_now=True, editable=False)
platform_description = models.CharField(max_length=30)
class Meta:
ordering = ('-created',)
def __unicode__(self):
return u'%s' % self.id
def __str__(self):
return '%s' % self.platform_description
def get_absolute_url(self):
return reverse('platforms_game_platforms_detail', args=(self.id,))
def get_update_url(self):
return reverse('platforms_game_platforms_update', args=(self.id,))
Serializer
class battlesSerializer(serializers.ModelSerializer):
class Meta:
model = models.battles
fields = (
'id',
'created',
'last_updated',
'wager',
'battle_rules',
'accepting_time',
'offer_expiration_time',
'battle_time',
'rake',
)
class game_platformsSerializer(serializers.ModelSerializer):
class Meta:
model = models.game_platforms
fields = (
'id',
'created',
'last_updated',
'platform_description',
)
You can use SerializerMethodField:
class battlesSerializer(serializers.ModelSerializer):
platform_description = serializers.SerializerMethodField()
def get_platform_description(self, obj):
# Use a try - except block if needed
return obj.platform_id.platform_description
class Meta:
model = models.battles
fields = (
'id',
'created',
'last_updated',
'wager',
'battle_rules',
'accepting_time',
'offer_expiration_time',
'battle_time',
'rake',
'platform_description', # add this field
)
Also, you could take a look over PEP8's naming conventions to write an elegant python code.