Problem with saving object in django-rest-framework - python

This is my view where I save Order object with values from frontend:
#api_view(['POST'])
#permission_classes([AllowAny])
def generate_bank_transfer_order(request):
if request.method == "POST":
body = json.loads(request.body)
first_name = body.get("firstName")
last_name = body.get("lastName")
full_name = f"{first_name} {last_name}"
today = datetime.now()
transaction_id= f'00{today.strftime("%S%M%H%d%m%y")}'
code_base = body.get('code')
try:
code = Code.objects.get(code = code_base)
new_order = Order(email=body.get("email"), message=body.get("message"),
city=body.get("city"), adress=body.get("adress"), postal_code=body.get("postalCode"),
phone=body.get("phone"), full_name=full_name, product_names=body.get("cart"),
shipment_fee=body.get("shipmentFee"), shipment_method=body.get("shipmentMethod"),
transaction_id=transaction_id, total_price=body.get("price"), code=code)
new_order.save()
return JsonResponse({"success":new_order.transaction_id})
except ObjectDoesNotExist:
new_order = Order(email=body.get("email"), message=body.get("message"),
city=body.get("city"), adress=body.get("adress"), postal_code=body.get("postalCode"),
phone=body.get("phone"), full_name=full_name, product_names=body.get("cart"),
shipment_fee=body.get("shipmentFee"), shipment_method=body.get("shipmentMethod"),
transaction_id=transaction_id, total_price=body.get("price"))
new_order.save()
return JsonResponse({"success":new_order.transaction_id})
This is my Order model:
class Order(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, blank=True, null=True)
message = models.TextField(max_length=1000, blank=True, null=True)
email = models.EmailField(max_length=255, blank=True, null=True)
city = models.CharField(max_length=75, default='')
adress = models.CharField(max_length=100)
postal_code = models.CharField(max_length=6)
phone = models.CharField(primary_key=True, max_length=9, validators=[RegexValidator(r'^\d{9}$/')])
full_name = models.CharField(max_length=100)
product_names = models.TextField(max_length=5000)
shipment_fee = models.IntegerField(default=0)
shipment_method = models.CharField(blank=True, null=True, max_length=50)
code = models.ForeignKey(Code, on_delete=models.SET_NULL, null=True)
transaction_id = models.CharField(max_length=150, default=0)
total_price = models.DecimalField(default=0, max_digits=12, decimal_places=2)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
accepted = models.BooleanField(default=False)
shipped = models.BooleanField(default=False)
def __str__(self):
return f"{self.email} : {self.transaction_id}"
def save(self):
if not self.created_at:
self.created_at = timezone.now()
self.updated_at = timezone.now()
return super(Order, self).save()
This piece of code is not perfect, but it saves the data I need. The problem is when I want to save another order, the previous one get updated instead of the next one being created. Any thoughts about what did I do wrong?

Try passing in arguments to the save method as described in the docs:
def save(self, *args, **kwargs):
if not self.created_at:
self.created_at = timezone.now()
self.updated_at = timezone.now()
super().save(*args, **kwargs)
I would also clean up the try/get:
new_order = Order(email=body.get("email"), message=body.get("message"),
city=body.get("city"), adress=body.get("adress"), postal_code=body.get("postalCode"),
phone=body.get("phone"), full_name=full_name, product_names=body.get("cart"),
shipment_fee=body.get("shipmentFee"), shipment_method=body.get("shipmentMethod"),
transaction_id=transaction_id, total_price=body.get("price"))
try:
code = Code.objects.get(code=code_base)
new_order.code = code
except ObjectDoesNotExist:
pass
new_order.save()
return JsonResponse({"success":new_order.transaction_id})

Related

Cannot assign "OrderItem.product" must be a "Product" instance

I am trying to create a "create order" endpoint, i keep getting
Cannot assign "<django.db.models.fields.related_descriptors.create_forward_many_to_many_manager.<locals>.ManyRelatedManager object at 0x7f50dad00f70>": "OrderItem.product" must be a "Product" instance.
heres my models
def product_images(instance, filename):
return f"product/{instance.product_name}/{filename}"
class Product(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(max_length=200, null=True, blank=True)
description = models.TextField()
date_created = models.DateTimeField(auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True)
is_active = models.BooleanField(default=True)
image = models.ImageField(
storage=MediaRootS3BotoStorage(),
upload_to="product_images",
null=True,
blank=True,
)
price = models.DecimalField(max_digits=10, decimal_places=2)
def __str__(self):
return self.name
def save(self, *args, **kw):
self.slug = slugify(f"{self.name}")
super(Product, self).save(*args, **kw)
# Ecommerce Models Store and Product
def store_images(instance, filename):
return f"{instance.store_name}/{filename}"
class Store(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(max_length=200, null=True, blank=True)
description = models.TextField()
date_created = models.DateTimeField(auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True)
is_active = models.BooleanField(default=True)
image = models.ImageField(upload_to="store_images", null=True, blank=True)
delivery_fee = models.DecimalField(max_digits=10, decimal_places=2, default=0.00)
address = models.CharField(max_length=100, null=True, blank=True)
phone_number = models.CharField(max_length=100, null=True, blank=True)
products = models.ManyToManyField("Product", through="StoresProduct")
def __str__(self):
return self.name
def save(self, *args, **kw):
self.slug = slugify(f"{self.name}")
super(Store, self).save(*args, **kw)
class Cart(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
product = models.ManyToManyField("Product", through="StoresProduct")
quantity = models.IntegerField(default=1)
date_created = models.DateTimeField(auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.user.email
def get_total(self):
return self.product.price * self.quantity
class StoresProduct(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
seller = models.ForeignKey(Store, on_delete=models.CASCADE)
price = models.DecimalField(max_digits=10, decimal_places=2, default=0.00)
quantity = models.IntegerField(blank=True, null=True)
date_created = models.DateTimeField(auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True)
is_active = models.BooleanField(default=True)
cart = models.ForeignKey(
Cart,
on_delete=models.CASCADE,
related_name="products",
default=None,
null=True,
blank=True,
)
product = models.ForeignKey(
Product,
on_delete=models.CASCADE,
related_name="+",
default=None,
null=True,
blank=True,
)
def __str__(self):
return f"{self.product.name} - {self.seller.name}"
class Meta:
unique_together = ["product", "seller"]
OrderStatus = (
("Pending", "Pending"),
("Delivered", "Delivered"),
("Cancelled", "Cancelled"),
("Processing", "Processing"),
)
class Order(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
date_created = models.DateTimeField(auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=100, choices=OrderStatus, default="Pending")
delivery_fee = models.DecimalField(max_digits=10, decimal_places=2, default=0.00)
total = models.DecimalField(max_digits=10, decimal_places=2, default=0.00)
order_id = models.CharField(max_length=100, null=True, blank=True)
order_items = models.ManyToManyField("Product", through="OrderItem")
store = models.ForeignKey(Store, on_delete=models.CASCADE, null=True, blank=True)
def __str__(self):
return self.user.email + " - " + self.order_id
def get_random_order_id(self):
order_id = str(uuid.uuid4()).replace("-", "").upper()[:10]
return order_id
# create order id with random string
def save(self, *args, **kwargs):
if not self.order_id:
self.order_id = self.get_random_order_id()
super(Order, self).save(*args, **kwargs)
class OrderItem(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
order = models.ForeignKey(Order, on_delete=models.CASCADE)
store = models.ForeignKey(Store, on_delete=models.CASCADE)
quantity = models.IntegerField(default=1)
date_created = models.DateTimeField(auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.product.name
and my views.py
#create order with orderitems
#swagger_auto_schema(method="post", request_body=OrderSerializer)
#api_view(["POST"])
#permission_classes((permissions.AllowAny,))
#authentication_classes([TokenAuthentication])
def create_order(request):
"""
Creates an order then creates an orderitem
"""
user = request.user
serializer = OrderSerializer(data=request.data)
if serializer.is_valid():
serializer.save(user=user)
order_id = serializer.data["id"]
order = Order.objects.get(pk=order_id)
cart = user.cart_set.all()
for item in cart:
OrderItem.objects.create(
order=order,
product=item.product,
quantity=item.quantity,
)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
#swagger_auto_schema(method="post", request_body=AddToCartSerializer)
#api_view(["POST"])
#permission_classes((permissions.AllowAny,))
#authentication_classes([TokenAuthentication])
def add_to_cart(request):
"""
Adds a product to cart
"""
user = request.user
serializer = AddToCartSerializer(data=request.data)
if serializer.is_valid():
serializer.save(user=user)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Basically, users should be able to add products from various stores to their cart and when they are done they should be able to order.
I can't seem to figure out what i am doing wrongly, if there's a better way to do this do tell.I'm guessing my approach is problematic

How Can I Integrate Flutterwave Paymwnt Gate Way with Django

I am working on a Django Project where I want to collect payment in Dollars from Applicants on the portal, and I don't know how to go about it. Though I have been following an online tutorial that shows how to do it but the result I am having is different with the recent error which says 'module' object is not callable.
Remember that I have tested my configured environment and also imported it into my views on top of the page.
Profile model code:
class Profile(models.Model):
applicant = models.OneToOneField(User, on_delete=models.CASCADE, null = True)
surname = models.CharField(max_length=10, null=True)
othernames = models.CharField(max_length=30, null=True)
gender = models.CharField(max_length=6, choices=GENDER, blank=True, null=True)
nation = models.CharField(max_length=255, choices=NATION, blank=True, null=True)
state = models.CharField(max_length=20, null=True)
address = models.CharField(max_length=200, null=True)
phone = models.CharField(max_length=16, null=True)
image = models.ImageField(default='avatar.jpg', upload_to ='profile_images')
def __str__(self):
return f'{self.applicant.username}-Profile'
Education/Referee Model code:
class Education(models.Model):
applicant = models.OneToOneField(User, on_delete=models.CASCADE, null = True)
qualification = models.CharField(max_length=60, choices=INSTITUTE, default=None, null=True)
instition = models.CharField(max_length=40, null=True)
reasons = models.CharField(max_length=100, null=True)
matnumber = models.CharField(max_length=255, null=True)
reference = models.CharField(max_length=100, null=True)
refphone = models.CharField(max_length=100, null=True)
last_updated = models.DateTimeField(auto_now_add=False, auto_now=True)
def __str__(self):
return f'{self.applicant}-Education'
Submitted Model code:
class Submitted(models.Model):
applicant = models.OneToOneField(User, on_delete=models.CASCADE, null=True)
application = models.UUIDField(primary_key = True, editable = False, default=uuid.uuid4)
confirm = models.BooleanField()
approved = models.CharField(max_length=20, null=True)
date = models.DateTimeField(auto_now_add=True)
def save(self, *args, **kwargs):
self.application == str(uuid.uuid4())
super().save(*args, **kwargs)
def __unicode__(self):
return self.applicant
def __str__(self):
return f'Application Number: {self.application}-{self.applicant}'
Scholarship Model code:
class Scholarship(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null = True)
name = models.CharField(max_length=100, null = True)
description = models.CharField(max_length=200, null = True)
category = models.CharField(max_length=60, choices=INSTITUTE, default=None, null=True)
amount = models.FloatField()
date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f'WASU Scholarship: {self.name}-{self.name}'
My View for printing slip:
def AppSlip(request):
check_submited = Submitted.objects.get(applicant=request.user)
check_education = Education.objects.get(applicant = request.user)
candidate_edu = check_education.qualification
scholarship = Scholarship.objects.get(category=candidate_edu)
context = {
'candidate_edu':candidate_edu,
'scholarship':scholarship,
}
return render(request, 'user/slip.html', context)
My view for applicant to fill form for payment which I want their Profile captured automatically in the form:
def scholarship_detail(request, pk):
data = Scholarship.objects.get(id=pk)
if request.method=='POST':
form = PaymentForm(request.POST)
if form.is_valid():
user = Profile.objects.get(applicant=request.user)
name= user.surname
email = form.cleaned_data['email']
amount = form.cleaned_data['amount']
phone = form.cleaned_data['phone']
context = {'applicant':name, 'email':email, 'amount':amount, 'phone':phone}
return process_payment(request, context)
else:
form = PaymentForm()
ctx={
'form':form,
'product':data,
}
return render(request, 'user/scholarship.html', ctx)
My form code for Payment: How can query logged in user profile and fill into name, email, phone, amount from Scholarship Model into amount form filled.
class PaymentForm(forms.Form):
name = forms.CharField(label='Your name', max_length=100)
email = forms.EmailField()
phone=forms.CharField(max_length=15)
amount = forms.FloatField()
View code for processing Payment (Where I am suspecting the error). Though I have configured my env using django-dotenv with the Flutterwave Secret Key in it.
#login_required(login_url='user-login')
def process_payment(request, newContext={}):
auth_token= dotenv('SECRET_KEY')
hed = {'Authorization': 'Bearer ' + auth_token}
data = {
"tx_ref":''+str(math.floor(1000000 + random.random()*9000000)),
"amount":amount,
"currency":"KES",
"redirect_url":"http://localhost:8000/callback",
"payment_options":"card",
"meta":{
"consumer_id":23,
"consumer_mac":"92a3-912ba-1192a"
},
"customer":{
"email":email,
"phonenumber":phone,
"name":name
},
"customizations":{
"title":"WASU Scholarship 2022",
"description":"Best store in town",
"logo":"https://getbootstrap.com/docs/4.0/assets/brand/bootstrap-solid.svg"
}
}
url = ' https://api.flutterwave.com/v3/payments'
response = requests.post(url, json=data, headers=hed)
response=response.json()
link=response['data']['link']
return link
My payment Response View:
#require_http_methods(['GET', 'POST'])
def payment_response(request):
status=request.GET.get('status', None)
tx_ref=request.GET.get('tx_ref', None)
print(status)
print(tx_ref)
return HttpResponse('Finished')
Anticipating your prompt answers. Thanks

Populate a Django form field with data from a model

I'm have been struggling on this for 2 days, really. I want to populate Timesheet form field from Employees model as a select field / dropdown list.
Here are my files and I tried so far.
MODEL.PY
class Employees(models.Model):
# MONTHLY = 'MONTHLY'
# SEMIMONTHLY = 'SEMIMONTHLY'
# BIWKEEKLY = 'BIWKEEKLY'
# WEEKLY = 'WEEKLY'
# DAILY = 'DAILY'
PAY_PERIODS = [
('Monthly', 'Monthly'),
('Bi-weekly', 'Bi-weekly'),
('Weekly', 'Weekly'),
('Daily', 'Daily'),
]
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
is_active = models.BooleanField(default=True, verbose_name='Employee is actives')
first_name = models.CharField(max_length=50, verbose_name='First Name.', null=True, blank=False)
middle_name = models.CharField(max_length=50, verbose_name='Middle Name or Initials.', null=True, blank=True)
last_name = models.CharField(max_length=50, verbose_name='Last Name.', null=True, blank=False)
full_name = models.CharField(max_length=50, null=True, blank=True)
phone = PhoneField(blank=True, null=True)
email = models.EmailField(max_length=150, blank=True, null=True)
state = USStateField(null=True, blank=True)
street_address = models.CharField(max_length=150, blank=True, null=True, verbose_name='Street Address.')
zip_code = models.CharField(max_length=50, blank=True, null=True, verbose_name='Zip Code.')
hourly_rate = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
pay_frequency = models.CharField(max_length=100, choices=PAY_PERIODS, blank=True)
hire_date = models.TimeField(auto_now_add=True)
def __str__(self):
return self.full_name
def save( self, *args, **kwargs ):
self.full_name = f'{self.first_name} {self.middle_name} {self.last_name}'
super().save( *args, **kwargs )
class Timesheet(models.Model):
"""A timesheet is used to collet the clock-ins/outs for a particular day
"""
employer = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
full_name = models.ForeignKey(Employees, on_delete=models.CASCADE, null=True, blank=False, verbose_name='Select YOUR Name')
start_date = models.DateField(auto_now_add=True, null=True)
end_date = models.DateField(null=True, blank=False)
time_worked = models.DateField(null=True, blank=False)
def __str__(self):
return self.full_name
VIEWS.PY # I tried both function and class based views
class TimesheetView(CreateView):
model = Timesheet
fields = ('full_name', )
# form_class = TimesheetFrom
# queryset = Employees.objects.filter()
# print(queryset)
template_name = 'users/timesheet.html'
success_url = reverse_lazy('timesheet')
#login_required
def timesheet_view(request):
if request.method == 'POST':
form = TimesheetFrom(request.POST)
if form.is_valid():
emp = form.save(commit=False)
emp.user_id = request.user.pk
emp.save()
return redirect('dashboard')
else:
form = TimesheetFrom()
context = {
'form': TimesheetFrom(),
}
return render(request, 'users/timesheet.html', context)
FORM.PY
class TimesheetFrom(forms.Form):
class Meta:
model = Timesheet
fields = '__all__'
exclude = ('employer', )
#This is the current state of the form but I did tried many approaches.
I did search extensively here (Stackoverflow) but no use case for me. Any help will be greatly appreciated with a cup of coffee.

__str__ returned non-string (type Leads)

I am getting the following error and I am not able to figure it out:
TypeError: str returned non-string (type Leads)
class Leads(models.Model):
name = models.CharField(max_length=250, default=0)
contact_person_name = models.CharField(max_length=250, default=0 ,blank=True, null=True)
email = models.EmailField(max_length=250, default=0, blank=True, null=True)
created_by = models.ForeignKey("packsapp.Employee", on_delete=models.CASCADE, related_name='createdby')
def __str__(self):
return self.name
class Pfep(models.Model):
client = models.ForeignKey(Leads, on_delete=models.CASCADE, related_name='vendor_owner')
receiver = models.CharField(max_length=250, default=0 ,blank=True, null=True)
receiver_location = models.CharField(max_length=250, default=0 ,blank=True, null=True)
def __str__(self):
return self.client
class PPboxSol(models.Model):
box_length = models.IntegerField(default=0, blank=True, null=True)
box_breadth = models.IntegerField(default=0, blank=True, null=True)
box_height = models.IntegerField(default=0, blank=True, null=True)
created_on = models.DateField(auto_now_add=True)
pfep = models.ForeignKey(Pfep, on_delete=models.CASCADE, related_name='pfep_box_sol')
created_by = models.ForeignKey("packsapp.Employee", on_delete=models.CASCADE, related_name='ppbox_createdby')
Views.py
class PpboxsolFormView(CreateView):
model = PPboxSol
form_class = Ppboxsolform
template_name = 'pfep/PpboxsolForm.html'
def get_initial(self):
initial = super().get_initial()
initial['pfep'] = Pfep.objects.get(pk=self.kwargs['pk'])
return initial
def form_valid (self, form):
if self.request.user.employee.employee_role == 'admin':
product = form.save(commit=False)
product.created_by = Employee.objects.filter(user=self.request.user.id)[0]
product.save()
messages.success(self.request, 'The PP Box Solution was created with success!')
return redirect('emp:ppbox_table')
else:
messages.success(self.request, "You don't have permission to create Solution!")
return redirect('emp:ppbox_table')
return redirect('emp:pfep_table')
Urls.py
path('ppboxsol/add/<int:pk>/', PpboxsolFormView.as_view(), name='ppbox_form'),
Do I need to add def __str__(self): to model PPboxSol as well ?
Edit:
I have added the Leads model as well, but that also returns a str
add a lead field name you want to show for example user model if we want to show username so we need to use user.username
Try This:
class Pfep(models.Model):
client = models.ForeignKey(Leads, on_delete=models.CASCADE, related_name='vendor_owner')
receiver = models.CharField(max_length=250, default=0 ,blank=True, null=True)
receiver_location = models.CharField(max_length=250, default=0 ,blank=True, null=True)
def __str__(self):
return str(self.client.name)#name for example

Put request.user.email inside another model field

I try to get user email from user model and put it in a field on another model the code is working and the counter count perfect but the add line not this is the code:
models.py
class Posts(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(blank=True, max_length=100)
slug = models.SlugField(null=True, blank=True)
contain = models.TextField(blank=True)
post_image = models.ImageField(upload_to="post_img", default='post_img/humanity.jpg')
post_published = models.DateTimeField(blank=True, auto_now_add=True)
post_updated = models.DateTimeField(blank=True, auto_now=True)
post_deleted = models.BooleanField(default=False)
post_approved = models.BooleanField(default=False)
post_sponsored = models.CharField(max_length=100, null=True, blank=True, default = None)
post_sponsored_accepted = models.BooleanField(default=False)
def save(self, *args, **kwargs):
if not self.slug:
self.slug= slugify(self.title)
super(Posts, self).save(*args, **kwargs)
def __str__(self):
return f'Author: {self.author}, Title:{self.title}, Posted: {self.post_published}'
views.py
def post_check(request, pk):
pos = Posts.objects.get(pk=pk)
u = UserProfile.objects.get(user=request.user)
if u.sp_counter < 3:
pos.post_sponsored = request.user.email
u.sp_counter += 1
u.save()
messages.success(request, 'طلبك قيد المراجعة، الرجاء انتظار الموافقة')
return redirect('index')
else:
messages.warning(request, 'وصلت الحد الاقصى للكفالات')
return redirect('index')

Categories