Django ManyToMany field object automatically pre-fills - python

I have an PaypalOrder model that is created when someone orders from a website, and it has a ManyToManyField that connects it to multiple OrderItems. Whenever I create a PaypalOrder, it automatically lists every OrderItem that exists in the django admin panel. How do I only list the objects that I set it to connect to?
my models.py:
class OrderItem(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
quantity = models.IntegerField()
is_a_subscription = models.BooleanField(default=False)
subscription = models.ForeignKey('Subscription', on_delete=models.CASCADE, null=True, blank=True)
class PaypalOrder(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
items_and_quantities = models.ManyToManyField(OrderItem, blank=True, related_name="paypalorder")
full_name = models.CharField(max_length=100)
address1 = models.CharField(max_length=250)
address2 = models.CharField(max_length=250, null=True, blank=True)
city = models.CharField(max_length=100)
zipcode = models.CharField(max_length=20)
created_at = models.DateTimeField(auto_now_add=True)
total_paid = models.DecimalField(max_digits=10, decimal_places=2)
order_id = models.CharField(max_length=100, null=True, blank=True)
subscription_id = models.CharField(max_length=100, null=True, blank=True)
email=models.CharField(max_length=100, null=True)
country_code = models.CharField(max_length=100)
state = models.CharField(max_length=50, null=True)
my view:
order = PaypalOrder.objects.create(
user = user,
full_name= resp['subscriber']['name']['given_name'] + " " + resp['subscriber']['name']['surname'],
email = resp['subscriber']['email_address'],
city = resp['subscriber']['shipping_address']['address']['admin_area_2'],
state = resp['subscriber']['shipping_address']['address']['admin_area_1'],
address1 = resp['subscriber']['shipping_address']['address']['address_line_1'],
address2 = addr2,
zipcode = resp['subscriber']['shipping_address']['address']['postal_code'],
country_code = resp['subscriber']['shipping_address']['address']['country_code'],
total_paid = resp['billing_info']['last_payment']['amount']['value'],
order_id = "product_ID: " + resp['id'],
subscription_id = resp['plan_id'],
created_at = resp['create_time'],
)
order.save()
subscription = Subscription.objects.create(user = request.user, paypal_order = order)
order.items_and_quantities.set(OrderItem.objects.filter(pk=100))

I believe that you are being tricked by the Front end; look again; even when the Django admin displays all the items, only those related to PayPal orders are highlighted.

Related

Django Admin shows multiple instances for same primary key

I am struggling with a weird issue in Django (4.0.7) where multiple instances for the same primary key are shown in Django Admin, as well as when executing queries. I have displayed the primary keys to make clear that they are identical:
The two classes involved are Collection and Card, where every card has a foreign key to a collection.
class Collection(models.Model):
FREQUENCY_CHOICES = [('never', 'Never'), ('less', 'Less'), ('normal', 'Normal'), ('more', 'More')]
title = models.CharField(max_length=200)
author = models.CharField(max_length=200, blank=True, null=True)
user = models.ForeignKey(User, related_name='collections', on_delete=models.CASCADE)
type = models.CharField(max_length=10, choices=(('books', 'Books'), ('tweets', 'Tweets'), ('articles', 'Articles'), ('podcasts', 'Podcasts')))
custom_id = models.CharField(max_length=200, blank=True, null=True) # e.g. raindropref, amazon book id, etc.
url = models.URLField(blank=True, null=True)
tags = TaggableManager(blank=True)
connection = models.ForeignKey(Connection, related_name='collections', null=True, blank=True, on_delete=models.SET_NULL)
frequency = models.CharField(max_length=10, choices=FREQUENCY_CHOICES, default='normal')
class Card(models.Model):
text = models.TextField()
collection = models.ForeignKey(Collection, related_name='cards', on_delete=models.CASCADE, blank=True)
custom_id = models.CharField(max_length=200, null=True, blank=True)
author = models.CharField(max_length=200, null=True, blank=True)
url = models.URLField(blank=True, null=True)
created_at = models.DateTimeField(default=timezone.now)
favorite = models.BooleanField(default=False)
tags = TaggableManager(blank=True)
notes = models.TextField(blank=True, null=True)
location = models.IntegerField(blank=True, null=True)
I cannot fathom where the issue might be. I have already set up the databse from scratch, with no success.
Here is an example database query:
for c in Collection.objects.all():
print(c.pk, c.id)
12 12
12 12
12 12
13 13

NFT payment gateway django

How to accept NFTs on django site? Right now there are two models:
class Product(models.Model):
''' Product represents what a user can purchase to fund their wallet'''
TYPE_CHOICES = ((-1, "NONE"),(0,"BTC"),(1,'NFT'), (2, "FIAT"), (3, "DUMB"))
type = models.IntegerChoices(choices = TYPE_CHOICES, default = -1, blank = False)
price = models.FloatField(default = 0.00, null=False, blank=False)
title = models.CharField(max_length=50)
# TODO qr_code = models.ImageField(upload_to='qr_codes', blank=True)
description = models.TextField()
# active = models.BooleanField Whether a product is active or not
objects = ProductManager()
class Invoice(models.Model):
''' The invoice represents a transaction when a user purchases a product'''
STATUS_CHOICES = ((-1,"Not Started"),(0,'Unconfirmed'), (1,"Partially Confirmed"), (2,"Confirmed"), (3, "Wallet Credited"))
user = models.ForeignKey(User, on_delete = models.CASCADE)
product = models.ForeignKey("Product", on_delete=models.CASCADE)
status = models.IntegerField(choices=STATUS_CHOICES, default=-1)
order_id = models.CharField(max_length=250)
address = models.CharField(max_length=250, blank=True, null=True)
btcvalue = models.IntegerField(blank=True, null=True)
received = models.IntegerField(blank=True, null=True)
txid = models.CharField(max_length=250, blank=True, null=True)
rbf = models.IntegerField(blank=True, null=True)
created_at = models.DateField(auto_now=True)
objects = InvoiceManager()
We want to accept NFTs as one sort of product such that users are able to send us NFTs and the backend credits their accounts with those NFTs. Is there a good package/service that does this?

How can I split orders by attributes in my API

I have a method that creates orders from the user's cart. For the courier to take an order from different restaurants, the order is divided into several. But at the moment I'm splitting the order just by the dish in the cart. How to make an order split by restaurants? that is, if a user orders 5 dishes from two different restaurants, then 2 orders were formed.
views.py
#action(methods=['PUT'], detail=False, url_path='current_customer_cart/add_to_order')
def add_cart_to_order(self, *args, **kwargs):
cart = Cart.objects.get(owner=self.request.user.customer)
cart_meals = CartMeal.objects.filter(cart=cart)
data = self.request.data
for cart_meal in cart_meals:
order = Order.objects.create(customer=self.request.user.customer,
cart_meal=cart_meal,
first_name=data['first_name'],
last_name=data['last_name'],
phone=data['phone'],
address=data.get('address', self.request.user.customer.home_address),
restaurant_address=cart_meal.meal.restaurant.address,
)
order.save()
return response.Response({"detail": "Order is created", "added": True})
models.py
class Order(models.Model):
"""User's order"""
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name='related_orders')
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
phone = models.CharField(max_length=20)
cart_meal = models.ForeignKey(CartMeal, on_delete=models.CASCADE, null=True, blank=True)
restaurant_address = models.CharField(max_length=1024, null=True)
address = models.CharField(max_length=1024)
status = models.CharField(max_length=100, choices=STATUS_CHOICES, default=STATUS_NEW)
created_at = models.DateTimeField(auto_now=True)
delivered_at = models.DateTimeField(null=True, blank=True)
courier = models.OneToOneField('Courier', on_delete=models.SET_NULL, null=True, blank=True)
class CartMeal(models.Model):
"""Cart Meal"""
user = models.ForeignKey('Customer', on_delete=models.CASCADE)
cart = models.ForeignKey('Cart', verbose_name='Cart', on_delete=models.CASCADE, related_name='related_meals')
meal = models.ForeignKey(Meal, verbose_name='Meal', on_delete=models.CASCADE)
qty = models.IntegerField(default=1)
final_price = models.DecimalField(max_digits=9, decimal_places=2)
class Meal(models.Model):
"""Meal"""
title = models.CharField(max_length=255)
description = models.TextField(default='The description will be later')
price = models.DecimalField(max_digits=9, decimal_places=2)
discount = models.IntegerField(default=0)
restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE, null=True)
slug = models.SlugField(unique=True)
class Restaurant(models.Model):
"""Restaurant"""
name = models.CharField(max_length=255)
slug = models.SlugField(unique=True)
address = models.CharField(max_length=1024)
owner = models.ForeignKey('Restaurateur', on_delete=models.CASCADE, null=True)
meals = models.ManyToManyField('Meal', related_name='related_restaurant', blank=True)
How can I do this, please help me
You can group your meals with respect to resturants.
import itertools
from core.models import CartMeal, Order
for restaurant, cart_meals in itertools.groupby(CartMeal.objects.order_by('meal__restaurant'), lambda s: s.meal.restaurant):
order = Order.objects.create(
customer=self.request.user.customer,
first_name=data['first_name'],
last_name=data['last_name'],
phone=data['phone'],
address=data.get('address', self.request.user.customer.home_address),
restaurant_address=cart_meal.meal.restaurant.address,
)
order.cart_meal.set([cart_meal for cart_meal in cart_meals])
Ref: The answer is formulated by taking help from following answer.
https://stackoverflow.com/a/57897654/14005534

User object has no attribute customer

I am trying to create cart using django but i am getting this error. while I try to check that the user is authenticated or no i used customer = request.user.customer but it says user has no attribute customer
Here is my views.py
def cart(request):
if request.user.is_authenticated:
customer = request.user.customer
order, created = OrderModel.objects.get_or_create(customer=customer, complete=False)
items = order.orderitem_set.all()
else:
items = []
context = {}
return render(request, 'Home/cart.html', context)
here is my models.py
class CustomerModel(models.Model):
user = models.OneToOneField(User, on_delete = models.CASCADE, null=True, blank=True, default='')
customer_name = models.CharField(max_length=1000, null=True)
customer_phone = models.CharField(max_length=20, null=True)
def __str__(self):
return self.customer_name
class OrderModel(models.Model):
customer = models.ForeignKey(CustomerModel, on_delete=models.SET_NULL, null=True, blank=True)
order_date = models.DateTimeField(auto_now_add=True)
complete = models.BooleanField(default=False,null=True,blank=True)
transaction_id = models.CharField(max_length=1000, null=True)
def __str__(self):
return str(self.id)
class OrderItem(models.Model):
product = models.ForeignKey(ProductModel, on_delete=models.SET_NULL, null=True, blank=True)
order = models.ForeignKey(OrderModel, on_delete=models.SET_NULL, null=True, blank=True)
quantity = models.IntegerField(default=0, null=True, blank=True)
date_added = models.DateTimeField(auto_now_add=True)
class Address(models.Model):
customer = models.ForeignKey(CustomerModel, on_delete=models.SET_NULL, null=True, blank=True)
order = models.ForeignKey(OrderModel, on_delete=models.SET_NULL, null=True, blank=True)
address = models.CharField(max_length=10000)
city = models.CharField(max_length=1000)
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.address
I am stuck here and cant understand what to do.
I think changing the line customer = request.user.customer to customer = request.user.customermodel may solve your problem. If you want to use customer = request.user.customer add related name to your CustomerModel's field:
user = models.OneToOneField(User, on_delete = models.CASCADE, null=True, blank=True, default='', related_name='customer')
Note: Make sure that your user object has a related profile.
For example add an extra condition to your codes like following:
if hasattr(request.user, 'customer'): # If you have related name otherwise use customermodel
customer = request.user.customer
else:
# Return a proper message here
Because if your user object has no related profile this line of code will raise RelatedObjectDoesNotExist error type.
For the user field of the CustomerModel, you must set "related_name" and "related_query_name" to "customer":
user = models.OneToOneField(User, on_delete = models.CASCADE, null=True, blank=True, default='', related_name='customer', related_query_name='customer')
You have to set the "related_name" parameter in your CustomerModel customer field for reverse access
user = models.OneToOneField(User, related_name="user", on_delete = models.CASCADE, null=True, blank=True, default='')
if you don't set the related name django will generate field name + "_set" for the access (user_set in your example)

Multiple field foreign key in django

I have two models in django with definitions below.
CreativeStatus model :
class RtbdCreativeStatus(models.Model):
creative_id = models.CharField(max_length=500, primary_key=True)
advertiser_id = models.CharField(max_length=100, primary_key=True)
exposure_level = models.CharField(max_length=125)
modified_on = models.DateTimeField()
modified_by = models.CharField(max_length=100)
class RtbdCreative(models.Model):
id = models.AutoField(primary_key=True)
advertiser_id = models.ForeignKey(RtbdCreativeStatus, on_delete=models.CASCADE)
creative_id = models.ForeignKey(RtbdCreativeStatus, on_delete=models.CASCADE)
country_id = models.IntegerField()
adm = models.CharField(max_length=255, null=True, blank=True)
sample_url = models.CharField(max_length=500)
landing_page = models.CharField(max_length=500, null=True, blank=True)
html = models.CharField(max_length=500)
creative_attributes = models.CommaSeparatedIntegerField(max_length=150, null=True, blank=True)
advertiser_domains = models.CharField(max_length=500)
description = models.CharField(max_length=500, null=True, blank=True)
created_on = models.DateTimeField(auto_now=True, auto_now_add=True)
creative_type = models.CharField(max_length=50, null=True, blank=True)
demand_source_type_id = models.IntegerField()
revalidate = models.BooleanField(default=False)
(creative_id, advertiser_id ) combination is unique in my CreativeStatus table . I want that combination to be my foreign key for Creative table. I tried adding it but i get this error .
1)How do i achieve this join with two key combination as my foreign key .
2)What should be my query to fetch all the creatives with their status from CreativeStatus table .
UPDATE 1
on reading the answers below , i updated my model as mentioned below :
class RtbdCreative(models.Model):
id = models.AutoField(primary_key=True)
advertiser_id = models.ForeignKey(RtbdCreativeStatus, to_field='advertiser_id', related_name='advertiser', db_column='advertiser_id', on_delete=models.CASCADE)
creative_id = models.ForeignKey(RtbdCreativeStatus, to_field='creative_id', related_name='creative', db_column='creative_id', on_delete=models.CASCADE)
country_id = models.IntegerField()
adm = models.CharField(max_length=255, null=True, blank=True)
sample_url = models.CharField(max_length=500)
landing_page = models.CharField(max_length=500, null=True, blank=True)
html = models.CharField(max_length=500)
creative_attributes = models.CommaSeparatedIntegerField(max_length=150, null=True, blank=True)
advertiser_domains = models.CharField(max_length=500)
description = models.CharField(max_length=500, null=True, blank=True)
created_on = models.DateTimeField(auto_now=True, auto_now_add=True)
creative_type = models.CharField(max_length=50, null=True, blank=True)
demand_source_type_id = models.IntegerField()
revalidate = models.BooleanField(default=False)
Now i am getting this error . I have combination of advertiser_id , craetive_id as unique . But django expects both to be unique. What can i do to make it work ?
As mentioned in ERRROS, you need to add related_name as argument, when you want to add more than one foreign key for same Model.
class Creative(models.Model):
id = models.AutoField(primary_key=True)
advertiser_id = models.ForeignKey(RtbdCreativeStatus,
related_name="Advertiser", on_delete=models.CASCADE)
creative_id = models.ForeignKey(RtbdCreativeStatus,
related_name="Creative",
on_delete=models.CASCADE)
country_id = models.IntegerField()
adm = models.CharField(max_length=255, null=True, blank=True)
sample_url = models.CharField(max_length=500)
landing_page = models.CharField(max_length=500, null=True, blank=True)
html = models.CharField(max_length=500)
creative_attributes = models.CommaSeparatedIntegerField(
max_length=150, null=True, blank=True)
advertiser_domains = models.CharField(max_length=500)
description = models.CharField(max_length=500, null=True, blank=True)
created_on = models.DateTimeField(auto_now=True, auto_now_add=True)
creative_type = models.CharField(max_length=50, null=True, blank=True)
demand_source_type_id = models.IntegerField()
revalidate = models.BooleanField(default=False)
I just saw a parameter as to_fields for models.ForeignObject, superclass of models.ForeignKey. It might be used in this case for defining foreign key for composite primary key or unique keys.
advertiser_creative_id = models.ForeignObject(RtbdCreativeStatus, to_fields=['advertiser_id', 'creative_id'], related_name='abc', on_delete=models.CASCADE)
There is a from_fields parameter as well. It can be used to map the fields with to_fields.
Refer https://docs.djangoproject.com/en/2.2/_modules/django/db/models/fields/related/
When you add multiple ForeignKeys towards same table, you should override the related_name option of your fields, so that the fields could be distinguished easily.
You could implement a custom validation for checking uniqueness of the creative_id and advertiser_id,
class Creative(models.Model):
advertiser_id = models.ForeignKey(CreativeStatus,
related_name="advertisers")
creative_id = models.ForeignKey(CreativeStatus,
related_name="creatives")
def clean(self):
data = self.cleaned_data
if not data['advertiser_id'] == data['creative_id']:
raise ValidationError("Unique Constraint failed {}, {}".format(self.advertiser_id, self.creative_id))
return data
You could query your creatives from CreativeStatus using the related name.
creative_status_obj = CreativeStatus.objects.get(pk=some_pk)#or any query.
#All creatives of the given object can be queried using reverse relation.
creatives = creative_status_obj.creatives.all()

Categories

Resources