Reference individual field of model in another model? - python

I have three models so far:
class clientCode(models.Model):
unique_id = models.CharField(max_length=9, blank=False)
def __str__(self):
return self.unique_id
class clientAccount(models.Model):
clientCode = models.ForeignKey(ClientCode,
on_delete=models.CASCADE, related_name='clientBusiness',null=True)
clientAccount = models.CharField(max_length=13, blank=False)
clientName = models.CharField(max_length=45, blank=False)
class assets(models.Model):
assetName = models.CharField(max_length=45, blank=False)
assetCurrency = models.CharField(max_length=45, blank=False)
assetCode = models.CharField(max_length=15, blank=False)
def __str__(self):
return self.assetName
Now, I would like to have a model containing ALL the fields from the above + an amount and transaction.
I started as so...
class Holdings(models.Model):
holdingsName = models.ManyToManyField(assets)
The issue is this, while this returns the assetName which is what I'd like, how do I retrieve the assetCurrency?
I guess I need to know: How do I reference an individual field from one model another model?
I am truly lost on how to do this, i've tried various ForeignKey, ManytoMany.. Is the correct approach to build a form that includes all the fields and posts to said model?
To clarify, I would essentially like clientAccount and assets to remain as lists, and the Holdings model fields to be dropdowns relating to these models?
Sorry if this is unclear and thanks in advance for any help! - I'm sure Ive got the wrong end of the stick on how to build the models.

Ok you need to first of all determine how are your models related to each other or what are the relationships between ClientCode, ClientAccount, Assets and Holdings.
As an example, loosely defined holdings are stocks, property or other finanical assets in someone's possesion. So your models for holdings and assets could be something like that.
Also please follow the Django Naming Conventions for your code. I have changed field/model names to reflect that below. Link here
class Asset(models.Model)
asset_name = models.CharField(max_length=45, blank=False)
asset_currency = models.CharField(max_length=45, blank=False)
asset_code = models.CharField(max_length=15, blank=False)
def __str__(self):
return self.asset_name
class Holding(models.Model)
holding_name = models.CharField(max_length=50)
assets = models.ManyToManyField(Asset, related_name='holdings',
through='HoldingAsset')# if you want some more explicit fields on the through model
def __str__(self):
assets = self.assets.all()
asset_currencies = [asset.asset_currency for asset in assets]
return '%s -- %s' % (self.holding_name, self.asset_currencies)
Now if you get a holding object like this (ignoring any unhandled errors here)
holding = models.Holding.objects.get(holding_name='Test_Holdings')
to access your assets and their currencies , you could do something like this.
assets = holding.assets.all()
asset_currencies = [asset.asset_currency for asset in assets]
To load holdings based on assets, or vice-versa, you will need to use modelforms and use a chained drop-down approach.

Related

Get max value from a set of rows

This question is in relation to project 2 of the cs50 course which can be found here
I have looked at the following documentation:
Django queryset API ref
Django making queries
Plus, I have also taken a look at the aggregate and annotate things.
I've created the table in the template file, which is pretty straight forward I think. The missing column is what I'm trying to fill. Image below
These are the models that I have created
class User(AbstractUser):
pass
class Category(models.Model):
category = models.CharField(max_length=50)
def __str__(self):
return self.category
class Listing(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
description = models.TextField()
initial_bid = models.IntegerField()
category = models.ForeignKey(Category, on_delete=models.CASCADE)
date_created = models.DateField(auto_now=True)
def __str__(self):
return self.title
class Bid(models.Model):
whoDidBid = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
list_item = models.ForeignKey(Listing, default=0, on_delete=models.CASCADE)
bid = models.IntegerField()
category = models.ForeignKey(Category, on_delete=models.CASCADE)
date = models.DateTimeField(auto_now=True)
def __str__(self):
return_string = '{0.whoDidBid} {0.list_item} {0.bid}'
return return_string.format(self)
This is the closest I could come to after a very long time. But the result I get is just the number 2. Ref image below
Listing.objects.filter(title='Cabinet').aggregate(Max('bid'))
Where 'Cabinet' is a Listing object that I have created. And placed two bids on them.
So the question is, how do I get the Maximum bid value(i.e. 110 for this case) for a particular listing? Using the orm. I think if I used a raw sql query, I could build a dict, send it to the template with the queryset. Then while looping through the queryset, get the value for the key, where the key is the name of the listing or something along those lines. Nah, I would like to know how to do this through the ORM please.
Here's answer #1
Bid.objects.filter(list_item__title='Cabinet').prefetch_related('list_item').aggregate(Max('bid'))
What happens when you try this (sorry, I don't have any objects like this to test on):
Bid.objects.values(list_item__title).prefetch_related('list_item').annotate(Max('bid'))

How to iterate through all foreign keys pointed at an object in Django without using _set notation?

I am fairly new to Django, but I am working on an application that will follow a CPQ flow or Configure, Price, Quote. The user should select the product they would like to configure as well as the options to go with it. Once selected, the program should query an external pricing database to calculate price. From there the program should output the pricing & text data onto a PDF quote. I was able to get the application working using the specific product inheriting from a base product class. The issue is now that I've created a second product child class, I cannot use a singular "related_name". I've omitted the lists associated with the drop down fields to help with readability, but I've posted my models.py file below.
Is there a way I can iterate through Product objects that are pointing to a Quote object with a foreign key? A lot of answers I've found on SO relating to this were able to be solved either by specifying the "_set" or "related_name". I've seen other answers use the select_related() method, however, I can't seem to get the query right as the program won't know which set it needs to look at. A quote could have any mix of product instances tied to it, so am unsure how to handle that query. Again, I have been using django under 6 months, so I am a bit green. I am not sure if I am just not fundamentally understanding the big picture here. I thought about instead of using inheritance, to make Product a standalone class and to save the Compact or WRC info to it so I could just use one "related_name", but also thought that would just create another nested layer that would still fail.
Any help would be very appreciated! I've definitely hit the wall.
models.py
class Quote(models.Model):
project_name = models.CharField(max_length=256,blank=True)
customer_first_name = models.CharField(max_length=256,blank=True)
customer_last_name = models.CharField(max_length=256,blank=True)
company_name = models.CharField(max_length=256, blank=True)
address1 = models.CharField(max_length=256, blank=True, help_text ="Address")
address2 = models.CharField(max_length=256, blank=True)
city = models.CharField(max_length=256, blank=True, default="")
state = models.CharField(max_length=256, blank=True, default="")
zip_code = models.CharField(max_length=256, blank=True, default="")
country = models.CharField(max_length=256, blank=True, default="")
phone = PhoneField(blank=True)
email = models.EmailField(max_length=254,blank=True)
grand_total = models.FloatField(default=0)
create_date = models.DateTimeField(default = timezone.now)
class Product(models.Model):
class Meta:
abstract = True
price = models.FloatField(default=0)
total_price = models.FloatField(default=0)
quantity = models.IntegerField()
quote = models.ForeignKey('quote.Quote', on_delete=models.CASCADE)
quantity = models.IntegerField()
class Compact(Product):
base_size = models.CharField(choices=size, max_length = 256)
filter = models.CharField(choices=filter_list, max_length = 256)
product_name = models.CharField(max_length=256,default="Compact")
class WRC(Product):
base_size = models.CharField(choices=size, max_length = 256)
construction = models.CharField(choices=construction_list, max_length = 256)
outlet = models.CharField(choices=outlet_list, max_length = 256)
product_name = models.CharField(max_length=256,default="WRC")
I was able to figure out my issue, but wanted to answer in case someone came across a similar problem as myself. I was able to get get all product objects attached to a quote instance dynamically by modifying the get_context_data() method of my QuoteDetailView. I also needed to use the django library NestedObjects from django.contrib.admin.utils to grab all related objects to the quote instance. I also added a timestamp field to the Product class to be able to sort them. QuoteDetailView copied below.
class QuoteDetailView(FormMixin,DetailView):
model = Quote
form_class = ProductSelectForm
def get_context_data(self, **kwargs):
### collects related objects from quote
collector = NestedObjects(using=DEFAULT_DB_ALIAS)
collector.collect([kwargs['object']])
### slice off first element which is the quote itself
related_objects = collector.nested()
related_objects = related_objects[1:]
### get context data for qoute object
context = super().get_context_data(**kwargs)
context['now'] = timezone.now()
### if number of list items is above 0, then add them to the context
### and sort by timestamp
if len(related_objects) != 0:
context['items'] = sorted(related_objects[0], key=lambda x: x.timestamp)
return context

django model field depend on the value of another field

The use case of my application is I will have various fields to fill and among them one is Industry field and another is Segment Field for brand. The industry field is like category that brand falls into. So, if i choose the industry as Health Care for XYZ brand then the segment field should show the items like 'Ayurveda', 'Dental Clinics' (all health care related items). Basically, its like sub-category.
Here is a sample model
class Industry(models.Model):
name = models.CharField(max_length=150, blank=True, null=True)
class Meta:
verbose_name = 'Industry'
verbose_name_plural = 'Industries'
def __str__(self):
return self.name
class Segment(models.Model):
industry = models.ForeignKey(Industry, related_name='segment', on_delete=models.CASCADE)
name = models.CharField(max_length=150, blank=True, null=True)
class Meta:
verbose_name = 'Segment'
verbose_name_plural = 'Segments'
def __str__(self):
return f'{self.industry.name} - {self.name}'
class BusinessModel(models):
industry = models.ForeignKey(Industry, blank=False, null=False, related_name='industry', on_delete=models.CASCADE)
# segements = models.ForeignKey()
total_investment = models.CharField() # will be choice field
This is a simple model and I have not created Segment model as I am not sure how to approach to this problem. I am just curios to know, if for such case, do i have to something special in models.py or in the view side. Such type of things get arise during development phase, thus, I want to be clear on problem solving pattern in django.
UPDATE
https://www.franchisebazar.com/franchisor-registration here if you choose industry inside Business model section, the segment will be updated accordingly.
You can have a 3 model design like
class Industry(models.Model):
name = models.CharField(max_length=150, blank=True, null=True)
class Segment(models.Model):
name = models.CharField(max_length=150, blank=True, null=True)
class Mapping(models.Model):
industry = models.ForeignKey(Industry)
segment = models.ForeignKey(Segment)
You need to define relations between your models. You can find documentation about ManyToMany relation here which is suitable in your case.
you can use ChainedForeginKey.. Check the below links
customizing admin of django to have dependent select fields
https://django-smart-selects.readthedocs.io/en/latest/installation.html

Tricky Django QuerySet with Complicated ForeignKey Traversals

I am adapting Jim McGaw's e-commerce site from Beginning Django E-Commerce for my client's use. My client sells builds of computers composed of a custom set of parts. The parts that go into a system will change. For instance, the Super Samurai system sold two years from now will have different parts than the one we sell tomorrow. So as we sell each Super Samurai system we need a snapshot of what parts went into the Super Samurai at the moment in time of the sale.
I am having a problem with the QuerySet that copies all of the parts from the table that maps parts to builds (i.e. the parts that go into the Super Samurai)...
class Build(models.Model):
build = models.ForeignKey(PartModel, related_name='+')
part = models.ForeignKey(PartModel, related_name='+')
quantity = models.PositiveSmallIntegerField(default=1)
class Meta:
abstract = True
unique_together = ('build', 'part')
def __unicode__(self):
return self.build.name + ' with ' + str(self.quantity) + ' * ' + \
self.part.family.make.name + ' ' + self.part.name
class BuildPart(Build):
pass
class Meta:
verbose_name = "Build Part"
I need to copy the build parts from the BuildPart table into the OrderBuildPart table...
class OrderBuildPart(Build):
orderItem = models.ForeignKey(OrderItem, unique=False)
class Meta:
verbose_name = "Ordered Build Part"
...so that in the future we know which parts went into so-and-so's build.
McGaw's e-commrece site doesn't allow for items to be bundles of other items. So rather than create some nightmarish scenario of two different tables (and two series of SKUs) for builds and their parts, I wanted a build to be just like any other part...
class PartModel(models.Model):
family = models.ForeignKey(PartFamily)
name = models.CharField("Model Name", max_length=50, unique=True)
slug = models.SlugField(help_text="http://www.Knowele.com/<b>*slug*</b>",
unique=True)
vpn = models.CharField("VPN", help_text="Vendor's Part Number",
max_length=30, blank=True, null=True)
url = models.URLField("URL", blank=True, null=True)
costurl = models.URLField("Cost URL", blank=True, null=True)
cost = models.DecimalField(help_text="How much knowele.com pays", max_digits=9, decimal_places=2, blank=True, null=True)
price = models.DecimalField(help_text="How much a customer pays", max_digits=9, decimal_places=2, blank=True, null=True)
isActive = models.BooleanField(default=True)
isBestseller = models.BooleanField(default=False)
isFeatured = models.BooleanField(default=False)
isBuild = models.BooleanField(default=False)
description = models.TextField(blank=True, null=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
buildpart = models.ManyToManyField('self', through='BuildPart',
symmetrical=False, related_name='+')
class Meta:
ordering = ['name']
verbose_name = "Product Model"
def __unicode__(self):
return self.name
def get_absolute_url(self):
from django.core.urlresolvers import reverse
return reverse('productdetail', args=[self.slug])
The buildpart field references the ManyToMany BuildPart table which allows a build to have many parts and for a part to be associated with many builds.
Through adapting McGaw's code I get pretty much what I need until I finalize the PayPal payment and try to record what parts went into the sold builds at the precise moment of sale...
def payment(request):
token = request.POST['token']
payer = request.POST['payer']
result = paypal.do_express_checkout_payment(request, token, payer)
if result['ACK'][0] in ['Success', 'SuccessWithWarning']:
cart = Cart.objects.get(cart_id=get_cart_id(request))
finalOrder = Order()
finalOrder.cart_id = get_cart_id(request)
finalOrder.token = token
finalOrder.corID = result['CORRELATIONID'][0]
finalOrder.payerID = payer
finalOrder.ipAddress = request.META['REMOTE_ADDR']
finalOrder.first = cart.first
finalOrder.last = cart.last
finalOrder.address = cart.address
finalOrder.email = cart.email
finalOrder.transactionID = result['PAYMENTINFO_0_TRANSACTIONID'][0]
finalOrder.status = 'f'
finalOrder.save()
for item in get_cart_items(request):
oi = OrderItem()
oi.cart_id = item.cart_id
oi.quantity = item.quantity
oi.product = item.product
oi.price = item.price()
oi.save()
if item.product.isBuild:
for part in get_build_parts(request, item):
bp = OrderBuildPart()
bp.build = part.build
bp.part = part.part
bp.quantity = part.quantity
bp.orderItem = oi
bp.save()
empty_cart(request)
return render(request, 'payment.html', locals())
Everything seems fine until we hit the get_build_parts function...
def get_build_parts(request, part):
return BuildPart.objects.filter(build__id=part__product__pk)
...where Django's post-mortem complains "NameError at /payment/ global name 'part__product__pk' is not defined"
How do I traverse these complicated relationships so my boss can look up what parts went into each customer's builds?
The value side of the lookup doesn't work the way you think it does. The double-underscore stuff is for the left-hand side only: in effect, it's a hack to get round Python's syntax requirements. On the right-hand side, you pass a normal expression, which can follow object relationships using the standard dot syntax:
return BuildPart.objects.filter(build__id=part.product.pk)
Try BuildPart.objects.filter(build=part__product) instead of what you have.
Also, it looks like your "post mortem" is coming from the webapp actually being used. You should be learning of problems like this from unit tests failing, not from an HTTP call.

Filter by presence in a model's set

I have a Customer model that has many Locations, i.e., there is a location_set attribute on the model that returns a list of locations. Each Location also has many customers, i.e., a customer_set attribute.
I have one customer instance with all of its corresponding attributes. What I want to do is return all other customers who are present in at least of the locations in the customer's location_set. Is there a clean way to do this without having to manually manipulate the queryset and make a ton of calls to the DB?
class Customer(AbstractUser):
current_location = models.ForeignKey('device.Location',
null=True, blank=True, related_name='customers_present')
default_location = models.ForeignKey('device.Location',
null=True, blank=True, related_name='default_customers')
class Location(models.Model):
name = models.CharField(max_length=50, help_text="The name of the location")
customers = models.ManyToManyField(settings.AUTH_USER_MODEL,
through='customer.Membership')
class Membership(models.Model):
customer = models.ForeignKey(Customer)
location = models.ForeignKey('device.Location')
date_joined = models.DateTimeField(auto_now_add=True)
Without your model definitions it is very difficult to provide an exact answer to your question, something like the below could work:
Customer.objects.filter(location__in=your_customer_instance.location_set.all()).exclude(pk=your_customer_instance.pk)

Categories

Resources