Add new item in many to many field via api in Django - python

I'm calling an API to update the my liked_products many to many model in Django but, when calling the prod ID to add the item to the list, I get the error:
AttributeError at /api/customer/like_product/
'ReturnDict' object has no attribute 'liked_products'
Here is my API:
#csrf_exempt
def updated_liked_products(request):
customer = get_user(request)
if not customer:
return JsonResponse({'invalid token'})
customer_details = CustomerDetailSerializer(CustomerDetails.objects.get(
customer=customer)).data
customer_details.liked_products.add(request.data['prodId'])
customer_details.save()
return JsonResponse({"success": 'updated'})
Customer Details Model:
age = models.IntegerField(default="21", blank=True)
address = models.CharField(
default='', max_length=254, null=True, blank=True)
nick_name = models.CharField(
default='', max_length=254, blank=True)
average_order = models.FloatField(default="0.0", blank=True)
completed_orders = models.IntegerField(default="0", blank=True)
customer = models.ForeignKey(
Customer, on_delete=models.CASCADE)
customer_type = MultiSelectField(
choices=CUSTYPE, default=CUSTYPE, max_length=100)
current_selfie = models.ImageField(
upload_to='sefies/', blank=True, default='')
email_confirmed = models.BooleanField(default=False)
last_signin = models.DateTimeField(default=timezone.now)
liked_products = models.ManyToManyField('Product')
needs_help_with = MultiSelectField(
choices=CATEGORIES, max_length=1000, default='')
phone = models.CharField(
I am using Postman to update the data like this so I can see the liked product field but, cannot access it.:

You're having this error because you're trying to access liked_products attribute on a serialized data that is an instance of ReturnDict and not CustomerDetails.
It seems like there is not much point in the serializer usage in this API so you should be able to achieve what you want with just this:
#csrf_exempt
def updated_liked_products(request):
customer = get_user(request)
if not customer:
return JsonResponse({'invalid token'})
customer_details = CustomerDetails.objects.get(customer=customer)
customer_details.liked_products.add(request.data['prodId'])
return JsonResponse({"success": 'updated'})

Related

How Do I Add Multiple Objects Inside A Foreign key in Django

How do I make my Django view create an author model as an instance, and then save multiple objects inside the foreign key?
I have tried making a author instance, and then setting the tiktok attribute of the author instance to a new tiktok model instance with the desc, likes, etc.
This just updated the previous value, not appending a new tiktok object.
Models.py
from django.db import models
# Create your models here.
class TikTok(models.Model):
slug = models.SlugField(max_length=300, null=True)
desc = models.TextField(max_length=500, blank=True)
likes = models.CharField(default=None, blank=True, max_length=100)
shares = models.CharField(default=None, blank=True, max_length=100)
comments = models.CharField(default=None, blank=True, max_length=100)
plays = models.CharField(default=None, blank=True, max_length=100)
videoUrl = models.CharField(default=None, blank=True, null=True, max_length=500)
videoImg = models.CharField(default=None, blank=True, null=True, max_length=500)
music = models.CharField(default=None, blank=True, null=True, max_length=500)
def __str__(self):
return self.desc
class Author(models.Model):
userhandle = models.CharField(max_length=100, blank=True)
email = models.CharField(max_length=150, null=True, blank=True)
verified = models.BooleanField(null=True)
followers = models.IntegerField(default=0)
tiktoks = models.ForeignKey(TikTok, on_delete=models.CASCADE, null=True, blank=True)
def __str__(self):
return self.userhandle
And then create the instances in my views.
I want one author model, and many tiktoks associated with it.
This is what the output should look like:
{
id: 1,
userhandle: 'user'
email: 'user#gmail.com'
verified: True
tiktoks: [
#multiple arrays of tiktoks
{
desc: 'desc1',
likes: 40,
...
},
{
desc: 'desc2',
likes: 40,
...
}
...
]
}
First you'd change the tiktok field to this, or similar
tiktoks = models.ManyToManyField(TikTok)
Super Basic View Using Form
def create_tiktok(request):
if request.method == 'POST':
authorObj = Author.objects.filter(pk=request.POST.get('pk')).first()
if authorObj:
form = TikTokForm(request.POST)
if form.is_valid():
o = form.save()
authorObj.tiktoks.add(o)
Example Remove
# format: model.field.action(obj)
authorObj.tiktoks.remove(TikTok.objects.get(pk=1))
Example Usage
authorObj = Author.objects.get(userhandle='Nealium')
# Looping through all
for i in authorObj.tiktoks.all():
print(i) # <TikTok Object>
# Fetching a specific
authorObj.tiktoks.filter(slug='test').first()
# Mass Adding
tiktokList = TikTok.objects.filter(slug__icontains='te')
authorObj.tiktoks.add(*tiktokList)
# Mass Remove
authorObj.tiktoks.add(*tiktokList)
# Clear entire field
authorObj.tiktoks.clear()
You could do this by 3 ways
Make TikTok field many to many
Make Outer table to store the author and the tiktok FK
Make tiktok field string and store the IDs like this 1,2,3

Django is annotating wrong Count (possibly duplicates?)

I have a model ChatMessage that has a field sender which is a ForeignKey to User model.
I'm trying to annotate a number of all the ChatMessage objects that haven't been read (eg. have seen_at__isnull=True).
For a given user, there is only one sent message with seen_at__isnull=True but Django returns 11.
User.objects.select_related(...).annotate(
sent_unread_messages=Count('sent_chat_messages',
filter=Q(sent_chat_messages__seen_at__isnull=True))).get(pk=1234).sent_unread_messages
do you know where is the problem?
EDIT:
class ChatMessageManager(models.Manager):
def get_queryset(self) -> models.QuerySet:
return super().get_queryset().select_related('sender', 'recipient')
def as_sender_or_recipient(self, user) -> models.QuerySet:
return self.get_queryset().filter(Q(sender=user) | Q(recipient=user))
class ChatMessage(BaseModel):
objects = ChatMessageManager()
sender = models.ForeignKey('users.User', verbose_name='Odosielateľ', null=True, blank=True,
on_delete=models.SET_NULL, related_name='sent_chat_messages')
recipient = models.ForeignKey('users.User', verbose_name='Adresát', null=True, blank=True,
on_delete=models.SET_NULL, related_name='received_chat_messages')
content = models.TextField('Obsah')
attachment = models.FileField('Príloha', null=True, blank=True)
attachment_filename = models.CharField('Názov prílohy', null=True, blank=True, max_length=128)
meta = models.JSONField(verbose_name='Meta', null=True, blank=True, help_text='must be JSON')
seen_at = models.DateTimeField('Prečítané o', null=True, blank=True)
class CustomUserManager(UserManager):
def get_queryset(self):
return super().get_queryset().select_related('staff_profile', 'client_profile').annotate(
sent_unread_messages=Count('sent_chat_messages',
filter=Q(sent_chat_messages__seen_at__isnull=True))).annotate(
received_unread_messages=Count('received_chat_messages',
filter=Q(received_chat_messages__seen_at__isnull=True))).annotate(
sent_latest_message=Subquery(
ChatMessage.objects.filter(sender=OuterRef('pk')).order_by('-created').values('content')[:1])).annotate(
sent_latest_message_dt=Subquery(
ChatMessage.objects.filter(sender=OuterRef('pk')).order_by('-created').values('created')[:1])).annotate(
received_latest_message=Subquery(
ChatMessage.objects.filter(recipient=OuterRef('pk')).order_by('-created').values('content')[
:1])).annotate(
received_latest_message_dt=Subquery(
ChatMessage.objects.filter(recipient=OuterRef('pk')).order_by('-created').values('created')[:1]))
can you try using .distinct() method (which removes the duplicate elements from a queryset) when getting the messages ?

Making a GET request with filter

My model is the following
class PokerRoom(models.Model):
STATUS = (("Pending", "Pending"), ("Finished", "Finished"))
status = models.CharField(
max_length=11,
choices=STATUS,
verbose_name=_("Status da Story"),
default="Pending",
)
name = models.CharField(max_length=200, verbose_name=_("room name"), validators=[alphanumeric])
slug = models.CharField(max_length=200, verbose_name=_("room slug"), null=True, blank=True)
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
styleCards = MultiSelectField(choices=CHOICES, default=FIBONACCI)
datetime = models.DateTimeField(null=True, blank=True)
date = models.CharField(max_length=10, null=True, blank=True)
user = models.ForeignKey(User, on_delete=DO_NOTHING)
first_name_user = models.CharField(
max_length=200, verbose_name=_("user name"), null=True, blank=True
)
deck = models.ForeignKey(Pack, on_delete=models.CASCADE)
index = models.IntegerField(
null=True, blank=True, verbose_name=_("story being voted")
)
I'm my application, I want to make a searchbar for "status" and "name" and do a GET request with those filter that would be provided by the client when he make the search. But I don't know how to do that in my views.py
I was thiking in a GET method like this, but I don't know how to get the planningName and planningStatus from the frontend.
def get(self, request, pk):
"""GET of PokerRoom historic"""
user = request.user
pk = self.kwargs["pk"]
planningName =
planningStatus =
moderatorRoom = PokerRoom.objects.values("id", "first_name_user", "date", "name", "status", "styleCards", "datetime", 'slug'
).filter(Q(user= user) | Q(name=planningName) | Q(status=planningStatus)).order_by("-datetime")
Can someone helpe me?
Suppose the name of the input field is planningName, you can get the value in views.py by using
planningName = request.GET.get('planningName')
planningStatus = request.GET.get('planningStatus')

Filter a user data using contains in Django

I have this model that records data in slug. The user has a relation with the award model. What am trying to do is list all login user's awards slug field data in the contain filter so i can use it to filter user's data.
NOTE : All the data in save in the SuccessfulTransactionHistory model field award is in slug format and SuccessfulTransactionHistory model has no foreign key relation to award and user
models.py
class Award(models.Model):
admin = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
image = models.ImageField(upload_to='award_images')
slug = models.SlugField(max_length=150, blank=True, null=True)
about_the_award = models.TextField(blank=True, null=True)
status = models.CharField(max_length=20, choices=STATUS_PUBLISHED, default='Closed')
price = models.DecimalField(max_digits=3, default='0.5', decimal_places=1, blank=True, null=True, validators = [MinValueValidator(0.1)])
bulk_voting = models.CharField(max_length=20, choices=BULK_VOTING, default='Closed')
amount = models.DecimalField(default=0.0, max_digits=19, decimal_places=2, blank=True,)
results_status = models.CharField(max_length=20, choices=RESULTS_PUBLISHED, default='private')
starting_date = models.DateTimeField()
ending_date = models.DateTimeField()
date = models.DateTimeField(auto_now_add=True)
class SuccessfulTransactionHistory(models.Model):
nominee_name = models.CharField(max_length=120)
transaction_id = models.CharField(max_length=120)
award = models.CharField(max_length=120)
amount = models.DecimalField(default=0.0, max_digits=19, decimal_places=2)
status = models.CharField(max_length=120, null=True, blank=True)
phone = models.CharField(max_length=120, null=True, blank=True)
date = models.DateTimeField(auto_now_add=True)
In my view.py
success_list = SuccessfulTransactionHistory.objects.filter(award__contains=request.user.award.slug).order_by('-date')
This is my error
'User' object has no attribute 'award'
``
Your User object has a lot of awards, because you use ForeignKey.
The relation is: One award has one User, but One user has one or more than one awards (award_set is the property name).
Solutions? Yes, of course,but depends on the context.
1- If the user has only one award, you can use OneToOneField, and your logic is ok.
2- If the user can have more than one Award, may be you need 2 steps.
Step 1: get all award slugs:
award_slugs = list(request.user.award_set.values_list('slug', flat=True))
where award_slugs is a list of slugs.
Step 2: Get success_list:
success_list = SuccessfulTransactionHistory.objects.filter(award__in=award_slugs)

Django : access data from serializer after saving it

I want to make an API to allow client to order online.
When the order is validated, I want to send an email to the client to confirm his order.
For that, I need the data that I just created (the order id, the delivery day and the delivery place).
This is my code : models.py :
class memberArea(AbstractBaseUser):
username = models.CharField(max_length=255)
email = models.EmailField(max_length=255, unique=True)
phone = models.TextField()
date_joined = models.DateTimeField(verbose_name='date joined', auto_now_add=True)
last_login = models.DateTimeField(verbose_name='last login', auto_now=True)
deliveryAddress = models.TextField()
postalCode = models.CharField(max_length=255)
forget = models.TextField(null=True, blank=True)
city = models.CharField(max_length=255)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
class order(models.Model):
user = models.ForeignKey(memberArea, on_delete=models.CASCADE)
comment = models.TextField(null=True, blank=True)
orderDay = models.DateTimeField(auto_now_add=True)
deliveryDay = models.DateField()
deliveryAddress = models.CharField(max_length=255)
state = models.CharField(max_length=255, null=True, blank=True, default="En attente")
price = models.TextField(null=True, blank=True)
response = models.TextField(null=True, blank=True)
class orderDetail(models.Model):
order = models.ForeignKey(order, on_delete=models.CASCADE)
product = models.ForeignKey(product, on_delete=models.CASCADE)
byProduct = models.ForeignKey(byProduct, on_delete=models.CASCADE)
quantity = models.CharField(max_length=255)
serializer.py :
class orderDetailSerializer(serializers.ModelSerializer):
class Meta:
model = orderDetail
fields = '__all__'
read_only_fields = ('order',)
class MakeOrderSerializer(serializers.ModelSerializer):
orderDetail = orderDetailSerializer(many=True)
class Meta:
model = order
fields = ['user', 'comment', 'deliveryAddress', 'deliveryDay', 'orderDetail']
def create(self, validated_data):
order_detail_data = validated_data.pop('orderDetail')
new_order = order.objects.create(**validated_data)
new_order.save()
for product in order_detail_data:
order_detail = orderDetail.objects.create(order=new_order, **product)
return new_order
views.py :
#Make an order
#api_view(['POST'])
def order(request, format=None):
if request.method == 'POST':
serializer = MakeOrderSerializer(data=request.data)
data = {}
if serializer.is_valid():
serializer.save()
data['response'] = "Your order went well"
delivery_date = serializer.data['deliveryDay']
delivery_place = serializer.data['deliveryAddress']
order_id = serializer.data['id']
message = "Thanks for your older.<br/>You will receive your order the <strong>{}</strong><br/>Delivery Place : <strong>{}/strong>.<br/>Order ID: <strong>{}</strong>.<br/>".format('delivery_day', 'delivery_address', 'order_id')
send_mail(
"Validation of your order !",
message,
"myaddress#gmail.com",
["useraddress#gmail.com"],
fail_silently=False,
)
return Response(data)
return Response(serializer.errors)
When I try to use my variables and run my code, this is what I get : Got AttributeError when attempting to get a value for field `orderDetail` on serializer `MakeOrderSerializer`. The serializer field might be named incorrectly and not match any attribute or key on the `order` instance. Original exception text was: 'order' object has no attribute 'orderDetail'.
Thanks by advance for helping me.
To access data from serializer you can use serializer.data['deliveryDate']. Similarly you can access serializer.data['orderDetail'] it will return a list, then you can iterate over it to access your other data.

Categories