How can I join two model in django - django

I want to join two model. I am using postgresql. But the problem is I am not using any foreign key or many to field. But I am using same unique field for both table. So I want depends on thats field I can query from both table. "invoice" is the field. My models are
class Salesinvoice(models.Model):
id = models.AutoField(primary_key=True)
date = models.DateField(default=date.today)
invoice = models.CharField(max_length=20)
customer = models.CharField(max_length=100)
product_name = models.CharField(max_length=80)
price = models.DecimalField(max_digits=9, decimal_places=2, default=0.00)
quantity = models.IntegerField(default=0)
class Salespayment(models.Model):
id = models.AutoField(primary_key=True)
date = models.DateField(default=date.today)
invoice = models.CharField(max_length=20)
amount = models.DecimalField(max_digits=9, decimal_places=2, default=0.00)
discount = models.DecimalField(max_digits=9, decimal_places=2, default=0.00)
payment = models.DecimalField(max_digits=9, decimal_places=2, default=0.00)
What should be my Views for join above both table depends on invoice field.

Change your models, specifically:
SalesInvoice.invoice to be unique. If you cannot guarantee that this value will be unique - think again about your models relationships and the data.
make SalesPayment.invoice a ForeignKey field to SalesInvoice. Read about what on_delete=PROTECT does and what other options there are: https://docs.djangoproject.com/en/4.0/ref/models/fields/#foreignkey
you don't need to explicitly add id fields. This is done by Django anyway.
class SalesInvoice(models.Model):
date = models.DateField(default=date.today)
invoice = models.CharField(max_length=20, unique=True) # changed
customer = models.CharField(max_length=100)
product_name = models.CharField(max_length=80)
price = models.DecimalField(max_digits=9, decimal_places=2, default=0.00)
quantity = models.IntegerField(default=0)
class SalesPayment(models.Model):
date = models.DateField(default=date.today)
invoice = models.ForeignKey(SalesInvoice, on_delete=PROTECT) # changed
amount = models.DecimalField(max_digits=9, decimal_places=2, default=0.00)
discount = models.DecimalField(max_digits=9, decimal_places=2, default=0.00)
payment = models.DecimalField(max_digits=9, decimal_places=2, default=0.00)
Django will automatically support the following lookups and much more:
# get all payments for an invoice (could be empty)
payments = salesInvoice.salespayment_set.all() # this is a queryset
# get the invoice of a specific payment by date of a customer
payment = SalesPayment.objects.filter(customer=cust_pk, date=some_date).first()
if payment:
invoice = payment.invoice.invoice # this is your identifying string

For example, add a function to Salesinvoice class:
class Salesinvoice(models.Model):
id = models.AutoField(primary_key=True)
....
quantity = models.IntegerField(default=0)
def payment(self):
if Salespayment.objects.filter(invoice = self.invoice).count() == 1:
return Salespayment.objects.get(invoice = self.invoice)
else:
return None
So, when you need the related Salespayment in your views.py , just do:
salesinvoice = Salesinvoice.objects.get(...)
salespayment = salesinvoice.payment()
Same in templates:
{{salesinvoice.payment.anyfield}}

Related

How to save a field from another model to a variable NOT A FIELD

I have a model called Actual:
# Actual parts table
class Actual(models.Model):
vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE, verbose_name="Vendor name", related_name="actualvendor")
number = models.CharField("External part number", max_length=32, unique=True, blank=True, null=True)
description = models.CharField(max_length=64, blank=True)
pq = models.DecimalField(max_digits=7, decimal_places=2, default=1)
mrrp = models.DecimalField(max_digits=10, decimal_places=2)
# Model metadata
class Meta:
unique_together = ["vendor", "number"]
verbose_name_plural = "actual external parts"
# Display below in admin
def __str__(self):
return f"{self.number}"
I also have another model called Offer:
class Offer(models.Model):
sync_id = models.ForeignKey(Sync, on_delete=models.CASCADE, verbose_name="Internal part number", related_name="part")
discount = models.DecimalField(max_digits=3, decimal_places=2, default=0)
moq = models.DecimalField(max_digits=4, decimal_places=2, default=1)
status = models.CharField(max_length=20, choices=OFFERSTATUS_CHOICES, default=1)
actual = models.OneToOneField(Actual, on_delete=models.CASCADE)
# Display something in admin
def __str__(self):
return f"Offer {self.id} for {self.sync_id}"
# Calculate the price
def price(self):
return self.actual.mrrp * (1-self.discount)
I am trying to calculate the 'price' in the 'Offer' model using 'mrrp' but 'mrrp' is from the 'Actual' model.
I am able to do so with the code I've attached but as you can see in the django admin, the 'actual' shows up as a field. I don't want it to appear as a field. I just want 'actual' to be a variable that is equal to the value of 'mrrp'. That way I can use it to calculate the price.
Is there another way to reference fields from another model? Surely fields aren't the only way?

django objects.create method is too slow How to make faster?

multiple tables are mapped and, when I create post request,
it takes about 2~3 seconds. Is there any ways to fix it?
I guess it takes a long time on:
objects.create
for loop
product.objects.get
however, I am not able to find the better ways..
models:
#product, Order, OrderItems, ShippingAddress are mapped
class Order(models.Model):
user = models.ForeignKey(User, on_delete= models.CASCADE)
order_date = models.DateTimeField(auto_now=True)
is_paid = models.BooleanField(default=False)
paid_at = models.DateTimeField(auto_now=False, null=True, blank=True)
delivery_code = models.CharField(max_length=255, null=True, blank=True)
is_delivered = models.BooleanField(default=False)
delivered_date = models.DateTimeField(auto_now=False, null=True, blank=True)
total_price = models.DecimalField(max_digits=7, decimal_places=2, null=True)
shipping_price = models.DecimalField(max_digits=7, decimal_places=2, null=True)
payment_method = models.CharField(max_length=255,null=True)
def __str__(self):
return str(self.user)
class OrderItem(models.Model):
order = models.ForeignKey(Order, on_delete= models.CASCADE, null=True, blank=True)
product = models.ForeignKey(Product, on_delete= models.CASCADE)
name = models.CharField(max_length=200, null=True)
image = models.CharField(max_length=255, null=True)
qty = models.IntegerField(default=0, null=True)
price = models.DecimalField(max_digits=7, decimal_places=2, null=True)
def image_preview(self):
if self.image:
return mark_safe('<img src="{0}" width="55" height="55" />'.format(self.image))
else:
return '(No image)'
def __str__(self):
return str(self.product)
class ShippingAddress(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
order = models.OneToOneField(Order, on_delete=models.CASCADE, null=True, blank=True)
address = models.CharField(max_length=255, null=False)
city = models.CharField(max_length=255, null=False)
postal_code = models.CharField(max_length=255, null=False)
country = models.CharField(max_length=255, null=False)
def __str__(self):
return str(self.user)
view:
#permission_classes(IsAuthenticated)
#api_view(['POST'])
def OrderCreate(request):
data = request.data
user = request.user
order_items = data['orderItems']
#1.create order
order = Order.objects.create(
user = user,
total_price = data['totalPrice'],
shipping_price = data['shippingPrice'],
payment_method = data['paymentMethod']
)
#2.create orderItems
for i in order_items:
product = Product.objects.get(id=i['id'])
order_item = OrderItem.objects.create(
order = order,
product = product,
name = i['name'],
qty = i['qty'],
price = i['price'],
image = i['image']
)
#3. update stock
product.stock -= i['qty']
product.save()
#4.create shipping address
shipping_address = ShippingAddress.objects.create(
user = user,
order = order,
address = data['shippingAddress']['address'],
city = data['shippingAddress']['city'],
postal_code = data['shippingAddress']['postalCode'],
country = data['shippingAddress']['country'],
)
#5.serializing and save
serializer = OrderSerializer(order, many=False)
return Response(serializer.data)
You can instantiate the order_items without ever fetching the product, provided you have sufficient trust for the product ids in i['id']
for i in order_items:
# product = Product.objects.get(id=i['id'])
order_item = OrderItem.objects.create(
order = order,
product_id = i['id'], # set the id (magic suffix) without fetching product
name = i['name'],
qty = i['qty'],
price = i['price'],
image = i['image']
)
Instead of using .create you might instantiate these order_items as a list of unsaved instances and create them using OrderItem.bulk_create Read the bulk_create documentation; it has a number of caveats.
You could then run a loop updating the product stock field using an F expression to subtract from the current value in the product row without actually fetching a product object from the DB
for i in order_items:
product_id = i['id']
Product.objects.filter(
pk = product_id
).update(
stock = F('stock') - i['qty']
)
If you do fetch all the product instances into a list with updated stock values, there's also bulk_update which would let you apply all the updated stock values in a single DB operation. This might be better than doing them one by one with an F expression. You can also fetch them in bulk using
Product.objects.filter( pk__in=[ i['id'] for i in order_items ] )
(Warning, I don't think that there's any guarantee that the queryset contains the objects in the same order that you supply the i['id'] values )
Treat this as brainstorming. I'm not entirely certain that this is correct and I really don't know whether it will speed things up a lot, a little, or at all. I'd be interested to know, if you try it.

how to make relationship in django model

models.py
So,here i want to make Invoicemgmt model in which i can have multiple entries for Invoice table having
customer,project and Invoice_amount.
Basically,requirement is that whenever i see 'view_Invoice' of some id,first i will see all data of that
specific id on that page and then i want to have small table below for invoice_mgmt,where i can add amount received for that specific id invoice.
*so,i want to know what fields should i add in invoice_mgmt model for relationship "
class Invoice(models.Model):
company_choice = (
('VT_India', 'VT_India'),
('VT_USA', 'VT_USA'),
)
company = models.CharField(
max_length=30, blank=True, null=True, choices=company_choice)
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
project = models.ForeignKey(Allproject, on_delete=models.CASCADE)
invoice_title = models.CharField(max_length=15)
invoice_id = models.IntegerField(primary_key=True)
invoice_amount = models.IntegerField()
invoice_date = models.DateField(
blank=True, null=True)
invoice_duedate = models.DateField(
blank=True, null=True)
invoice_description = models.TextField()
def __str__(self):
return self.invoice_title
class Paymentmethod(models.Model):
paymentmethod_id = models.IntegerField(primary_key=True)
paymentmethod_name = models.CharField(max_length=15)
def __str__(self):
return self.paymentmethod_name
class Invoicemgmt(models.Model):
invoicemanagement_id = models.IntegerField(primary_key=True)
invoice_received = models.IntegerField()
date = models.DateField(
blank=True, null=True)
payment_method = models.ForeignKey(Paymentmethod, on_delete=models.CASCADE)
"So, basically i want to have multiple entries in invoice mgmt table for one specific invoice table id(one specific data)"

django: join two tables without foreignkey

I have two models which I want to join but they don't have any foreignkey
class Invoice(models.Model):
invoice_id = models.IntegerField(blank=True, null=True)
quotation_id = models.IntegerField(blank=True, null=True)
client_id = models.ForeignKey(tbl_customer, on_delete=models.CASCADE)
invoice_number = models.IntegerField(blank=True, null=True)
quotation_number = models.IntegerField(blank=True, null=True)
date = models.DateField(blank=True, null=True)
total_amount = models.DecimalField(max_digits=8, decimal_places=2, blank=True, null=True)
total_tax = models.DecimalField(max_digits=8, decimal_places=2, blank=True, null=True)
document_type = models.CharField(max_length=50, default='', blank=True, null=True)
and
class Invoice_Description(models.Model):
invoice_id = models.IntegerField(blank=True, null=True)
client_id = models.ForeignKey(tbl_customer, on_delete=models.CASCADE)
quotation_id = models.IntegerField(blank=True, null=True)
item_id = models.ForeignKey(tbl_item, on_delete=models.CASCADE)
item_qty = models.DecimalField(max_digits=8, decimal_places=2, blank=True, null=True)
item_unit_price = models.DecimalField(max_digits=8, decimal_places=2, blank=True, null=True)
Invoice contains information about the invoice document, its total price, date, etc while Invoice_Description keeps the records of items added on that particular invoice, item price, total quantity, discount on each item, etc.
I want to display all the records in reports with respect to items like
ITEM NAME CUSTOMER NAME INV. NO. QTY DOCUMENT TYPE UNIT PRICE SALE PRICE
Item1 Client1 01 950.00 1000.00
I have all the columns available from Invoice_Description except for the INV. NO. and DOCUMENT TYPE which are in the Invoice model.
I don't want to use a ForeignKey in this case because these models are already in use in many places, changing the database will require changes everywhere.
my problem is just that I want to join two models in Django but without ForeignKey so that I may get Invoice No. and Document Type of the corresponding row.
Any ideas on how can I do this??
If all you want to do is retrieve an InvoiceDescription object that belongs to a given Invoice, you could do the following:
invoice = Invoice.objects.first()
try:
description = InvoiceDescription.objects.get(invoice_id=invoice.invoice_id)
except InvoiceDescription.DoesNotExist:
description = None
I am assuming that the field invoice_id refers to the invoice ID. Although you didn't declare it using models.ForeignKey, it still acts as a foreign key in this situation. You just have to do the lookup manually.

django admin foreign key default value inline

I'm converting an ancient Client/Server app (Delphi) into a Django app for a small brick and morter bookstore (wife's).
Since most functions are admin, I'm using the Django admin interface with grappelli for some easier lookups.
I have 3 models: Book, Sale and Item.
class Book(TimeStampedModel):
"""
Books are described individually and are related to collections
as many to many. Every book in this system is unique - i.e. there are
not quantity fields. This is optimized for used book stores where book
condition is essential.
"""
STATUS_CHOICES = (
('IN STOCK', 'IN STOCK'),
('SOLD', 'SOLD'),
('ON LOAN', 'ON LOAN'),
('HOLD', 'HOLD'),
)
isbn = models.CharField(max_length=50, blank=True)
title = models.CharField(max_length=200, blank=False, db_index=True)
author = models.CharField(max_length=200, blank=True)
sell_price = models.DecimalField(max_digits=10,decimal_places=2, default=0)
description = models.TextField()
collections = models.ManyToManyField(Collection)
class Meta:
index_together = [
["author", "title"],
["status", "title", "author"],
]
def __unicode__(self):
return "%s [%d] - %s - $%.2f" % (self.title, self.id, self.book_type, self.sell_price)
#staticmethod
def autocomplete_queryset():
instock = Book.objects.filter(status="IN STOCK")
return instock
#staticmethod
def autocomplete_search_fields():
return("id__iexact", "title__istartswith",)
class Sale(TimeStampedModel):
"""
Sales group all sold items which may or may not be books and are sold to contacts.
We use a "generic" contact of "cash" for non named contacts
"""
PAYMENT_TYPE_CHOICES = ( ('Cash', 'Cash'), ('Charge', 'Charge'), ('Check', 'Check'))
contact = models.ForeignKey(Contact, null=True)
sale_date = models.DateField(blank=True,default=datetime.date.today, db_index=True)
payment_type = models.CharField(max_length=50, choices=PAYMENT_TYPE_CHOICES)
taxed = models.BooleanField(default=True)
tax_exempt_no = models.CharField(blank=True, max_length=50)
sales_tax = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
amt_tender = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
pct_discount = models.SmallIntegerField(blank=True, null=True)
amt_credit = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
amt_shipping = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
amt_due = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
tot_sale = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
tot_items = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
ordering = ['-sale_date']
def __unicode__(self):
return str(self.sale_date)
class Item(TimeStampedModel):
"""
Items are usually books sold on a sale. Items can also be entered manually
at time of sale if they are not books from inventory
"""
sale = models.ForeignKey(Sale)
book = models.ForeignKey(Book, null=True, blank=True)
item_desc = models.CharField(blank=True, max_length=200)
cost = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
sell_price = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
def __unicode__(self):
return self.item_desc
For the Sale form, I use an admin form with Tabular inline Items. Items are usually books (via a foreign key lookup), but can also be entered manually for non-inventory items so I have a sell_price both in the book model and in the item model.
class ItemInline(admin.TabularInline):
model = Item
raw_id_fields = ("book",)
autocomplete_lookup_fields = {
'fk': ['book'],
}
extra = 2
What I'd like to do in the foreign key lookup is to return the key of the book AND fill in the Item's sellprice with the sellprice from the book I looked up.
I have the basic lookup working just fine but can't find out how to set the item sellprice to the book's sellprice immediately after the lookup.
Any advice is appreciated! I have tried figuring out the objects to put some JS logic in but the inlines get object ids created dynamically, I think. I'm no JS expert.