How to implement class methods with attributes of another class? - python

I have three models, BoletoConfig(BilletConfig),Tickets and CategoryTicket, one ticket has a CategoryTicket and CategoryTicket has a BilletConfig, BilletConfig has an attribute with the days for the billet due, I want to create a method in the tickets class to calculate the due date.
I have doubts if I use the decorator #property or #classmethod, which would be the best choice and why? and how would i get the value of days_to_become_due from my BoletoConfig class in tickets?
This my /billets/models.BoletoConfig
class BoletoConfig(models.Model):
base_amount = models.DecimalField(
db_column='valor_base',
max_digits=10,
decimal_places=2,
verbose_name='valor base do boleto',
)
check_specialization_for_amount = models.BooleanField(
default=False,
db_column='especializacao_protocolo',
verbose_name='especialização do protocolo',
)
days_to_become_due = models.IntegerField(
db_column='dias_vencimento',
verbose_name='dias até vencimento',
)
class Meta:
db_table = 'boletos_boleto_configuracao'
verbose_name = 'boletos_configuração'
def __str__(self):
return self.base_amount
This my /tickets/models.tickets
class Ticket(TimestampedModel, permissions.TicketPermission):
"""A ticket requested by someone to address a situation"""
requested_by = models.ForeignKey(
settings.AUTH_USER_MODEL,
models.PROTECT,
db_column='requerido_por',
related_name='+',
)
show_ticket_for_request_user = models.BooleanField(
default=True,
db_column='mostrar_ticket_para_requerente',
)
message = models.CharField(
max_length=4000,
blank=True,
null=True,
db_column='mensagem',
)
status = models.ForeignKey(
Status,
models.PROTECT,
)
category = models.ForeignKey(
Category,
models.PROTECT,
)
files = models.CharField(max_length=4000, blank=True, null=True)
boleto_id = models.UUIDField(
db_column='boleto_id',
verbose_name='Uuid Boleto',
null=True,
blank=True,
)
#classmethod
def get_boleto_duo_date(self, category):
days_to_due = 'category__boleto_config__days_to_become_due'
return self.ticket.created_at + timedelta(days=days_to_due)
This my /tickets/models.CategoryTicket
class Category(TimestampedModel):
"""
Represents what the ticket is about.
EX: Change lesson attendance, change activity grade.
"""
.
.
.
.
boleto_config = models.ForeignKey(
BoletoConfig,
models.PROTECT,
db_column='boleto_config_id',
verbose_name='configuração de boleto',
null=True,
blank=True,
)

Related

Custom name for key in queryset

I have an Invoice query set. The invoice has an appointment object, that has a patient object that has a name attribute. I am trying to annotate so I can get the name of the patient as well. The rest of the fields return data okay. But the patient name doesn't. I have tried - F("appointment__patient__name") and also "appointment__patient__name". What am I missing here ?
def get_corporate_invoices(
start_date: date, end_date: date, corporate_uuid: str
) -> QuerySet[Invoice]:
return (
Invoice.objects.annotate(
entry_date=F("appointment_date"),
payment_method=Value("--", output_field=models.TextField()),
debit_amount=Round("amount", precision=2),
running_balance=Value(0.00, output_field=models.FloatField()),
patient_name=F("appointment__patient__name"),
)
.filter(
corporate_uuid=corporate_uuid,
appointment_date__gte=start_date,
appointment_date__lte=end_date,
isdeleted=False,
status="Cleared",
corporate_uuid__isnull=False,
)
.order_by("appointment_date", "concierge_rct_id")
.values(
"entry_date",
"payment_method",
"debit_amount",
"running_balance",
"patient_name"
)
)
models.py
class Invoice(models.Model):
transaction = models.ForeignKey(
Transaction,
on_delete=models.SET_NULL,
related_name="transaction_invoice",
blank=True,
null=True,
)
status = models.CharField(
max_length=25, choices=invoice_status_choices, default="Pending"
)
concierge_reference = models.TextField(blank=False, null=False)
concierge_rct_id = models.IntegerField(blank=False, null=True, unique=True)
appointment = models.JSONField(blank=False, null=True)
appointment_date = models.DateField(blank=False, null=True)
amount = models.FloatField(null=True, blank=True, default=0.00)
payment_mode = models.JSONField(blank=False, null=True)
This is what worked:
patient_name=Func(
F('appointment'), Value('patient'), Value('name'),
function='jsonb_extract_path_text'),
)

tabular inline admin where table are referenced in multiple tables

I was looking on customizing admin where i found tabularinline model which allow us to edit on the same page. But i got confused as my tables are reference in multiple places. I could not understand which model should i make tabular inline.
for example here is my model
class ProductType(ModelWithMetadata):
name = models.CharField(max_length=150, help_text="type of product. ex - accessories, apparel")
slug = models.SlugField(max_length=150, unique=True)
is_shipping_required = models.BooleanField(default=True)
class Meta:
ordering = ("slug",)
app_label="products"
class Category(MPTTModel, ModelWithMetadata):
name = models.CharField(max_length=128)
slug = models.SlugField(max_length=128)
description = models.TextField(blank=True)
parent = models.ForeignKey(
"self", null=True, blank=True, related_name="children", on_delete=models.CASCADE
)
objects = models.Manager()
tree = TreeManager()
class Meta:
verbose_name = "Category"
verbose_name_plural = "Categories"
def __str__(self):
return self.name
class Product(ModelWithMetadata, PublishableModel):
product_type = models.ForeignKey(
ProductType, related_name="products", on_delete=models.CASCADE
)
name = models.CharField(max_length=128)
slug = models.SlugField()
category = models.ForeignKey(
Category,
related_name="products",
on_delete=models.SET_NULL,
null=True,
blank=True,
)
isAvailable = models.BooleanField(default=True)
isDiscount = models.BooleanField(default=False)
charge_taxes = models.BooleanField(default=False)
updated_at = models.DateTimeField(auto_now=True, null=True)
class Meta:
verbose_name = "product"
verbose_name_plural = "products"
ordering = ("name",)
constraints = [
models.UniqueConstraint(
fields=["article_number", "slug"], name="unique article number and slug")
]
class ProductVariant(ModelWithMetadata):
sku = models.CharField(max_length=255, unique=True)
name = models.CharField(max_length=255, blank=True)
currency = models.CharField(
max_length=settings.DEFAULT_CURRENCY_CODE_LENGTH,
default=settings.DEFAULT_CURRENCY,
blank=True,
null=True,
)
price_override_amount = models.DecimalField(
max_digits=settings.DEFAULT_MAX_DIGITS,
decimal_places=settings.DEFAULT_DECIMAL_PLACES,
blank=True,
null=True,
)
product = models.ForeignKey(
Product, related_name="variants", on_delete=models.CASCADE
)
images = models.ManyToManyField("ProductImage", through="VariantImage")
track_inventory = models.BooleanField(default=True)
class BaseAssignedAttribute(models.Model):
assignment = None
values = models.ManyToManyField("AttributeValue")
class AttributeValue(models.Model):
name = models.CharField(max_length=250)
value = models.CharField(max_length=100, blank=True, default="")
slug = models.SlugField(max_length=255)
attribute = models.ForeignKey(
"Attribute", related_name="values", on_delete=models.CASCADE
)
class AssignedProductAttribute(BaseAssignedAttribute):
"""Associate a product type attribute and selected values to a given product."""
product = models.ForeignKey(
Product, related_name="attributes", on_delete=models.CASCADE
)
assignment = models.ForeignKey(
"ProductAttribute", on_delete=models.CASCADE, related_name="productassignments"
)
class Meta:
unique_together = (("product", "assignment"),)
class AssignedVariantAttribute(BaseAssignedAttribute):
"""Associate a product type attribute and selected values to a given variant."""
variant = models.ForeignKey(
ProductVariant, related_name="attributes", on_delete=models.CASCADE
)
assignment = models.ForeignKey(
"AttributeVariant", on_delete=models.CASCADE, related_name="variantassignments"
)
class Meta:
unique_together = (("variant", "assignment"),)
class AttributeVariant(models.Model):
attribute = models.ForeignKey(
"Attribute", related_name="attributevariant", on_delete=models.CASCADE
)
product_type = models.ForeignKey(
ProductType, related_name="attributevariant", on_delete=models.CASCADE
)
assigned_variants = models.ManyToManyField(
ProductVariant,
blank=True,
through=AssignedVariantAttribute,
through_fields=("assignment", "variant"),
related_name="attributesrelated",
)
class Attribute(models.Model):
name = models.CharField(max_length=30, unique=True)
slug = models.SlugField(max_length=250, unique=True)
product_types = models.ManyToManyField(
ProductType,
blank=True,
related_name="product_attributes",
through="ProductAttribute",
through_fields=("attribute", "product_type"),
)
product_variant_types = models.ManyToManyField(
ProductType,
blank=True,
related_name="variant_attributes",
through=AttributeVariant,
through_fields=("attribute", "product_type"),
)
class ProductAttribute(models.Model):
attribute = models.ForeignKey(
"Attribute", related_name="attributeproduct", on_delete=models.CASCADE
)
product_type = models.ForeignKey(
ProductType, related_name="attributeproduct", on_delete=models.CASCADE
)
assigned_products = models.ManyToManyField(
Product,
blank=True,
through=AssignedProductAttribute,
through_fields=("assignment", "product"),
related_name="attributesrelated",
)
I am confused on the tables AttributeValue, AssignedProductAttribute, AssignedVariantAttribute, AttributeVariant, Attribute and ProductAttribute. Attribute is related to ProductAttribute and is also related to AttributeVariant and AttributeValue. Similarly, in the case of variant.
I could not figure out which table should be inline and where should i reference that inlined table. Because of various relationship, i am not sure of those things.

Django. Choosing a specific field - relation one-to-many

I have two table and want to releated these with one-to-many.
One unity - many stat.
I try to select field but it not working.
Always my ForeignKey is Unit.name.
I want to use Unit.id as ForeignKey !!
I thought that the Unit.id can't be so for tests I tried another field Unit.name2, it also doesn't work.
https://docs.djangoproject.com/en/2.0/ref/models/fields/#django.db.models.ForeignKey.to_field
class Unit(models.Model) :
id = models.AutoField(primary_key=True)
name = models.CharField( max_length=20, unique=True)
name2 = models.CharField( max_length=20, unique=True)
rase = models.CharField( max_length=10 )
class Stat(models.Model) :
id = models.AutoField(primary_key=True)
unit_id = models.ForeignKey( Unit, to_field='name2', on_delete=models.CASCADE, verbose_name='unit_id',)
attack_type = models.CharField( 'attack_type', max_length=10 )
attack_speed = models.DecimalField( 'attack_speed', max_digits=5, decimal_places=4 )
attack_number = models.IntegerField( 'attack_number' )
Additional question.
If I left Unit.name as ForeignKey what happen when i change a Unit.name in the future? If name value will change in all related tables?
That's why I want to use Unit.id as a ForeignKey because Unit.id will not change but the Unit.name can.
I added unique=True also to AutoField in Unit model.
Also I change Unit.id to Unit.unit_id.
It seems it working.
class Unit(models.Model) :
unit_id = models.AutoField(primary_key=True, unique=True, verbose_name='unit_id', )
name = models.CharField( max_length=20, unique=True)
name2 = models.CharField( max_length=20, unique=True)
rase = models.CharField( max_length=10 )
def __str__( self ) :
string = 'unit_id: {} - {}'.format(self.unit_id, self.name)
return string
class Stat(models.Model) :
stat_id = models.AutoField(primary_key=True)
unit_id = models.ForeignKey( Unit, to_field='unit_id', on_delete=models.CASCADE, verbose_name='unit_id', )
attack_type = models.CharField( 'attack_type', max_length=10 )
attack_speed = models.DecimalField( 'attack_speed', max_digits=5, decimal_places=4 )
attack_number = models.IntegerField( 'attack_number' )
def __str__( self ) :
string = '{0} {1} stat'.format(self.unit_id, self.attack_type)
return string

Trigger a function in a Django model every time its variables change

I'm working on a Django model and I want to trigger a function every time its variables change. Here's my model:
class Cv(models.Model):
name = models.CharField(max_length=100)
position = models.ForeignKey(
OpenPosition,
on_delete=models.CASCADE,
null=True,
)
team = models.ForeignKey(
Team,
on_delete=models.CASCADE,
null=True
)
leader = models.ForeignKey(Leader, on_delete=models.CASCADE)
email = models.EmailField(
max_length=100,
null=False,
validators=[EmailValidator()],
blank=True
)
email_sent_status = models.BooleanField(default=False)
phone = models.CharField(
validators=[
RegexValidator(
regex=r'^(0\d{9,11})$',
message='''
Phone number must be started with 0 and has 10-12 digits
'''
)],
blank=True,
null=True,
max_length=20,
)
link = models.CharField(
max_length=150,
validators=[URLValidator()],
)
source = models.ForeignKey(CvSource, on_delete=models.CASCADE)
cv_status = models.CharField(
max_length=10,
choices=STATUS,
default='u',
)
schedule = models.DateTimeField(blank=True, null=True)
schedule_confirm = models.BooleanField(default=False)
interview_status = models.CharField(
max_length=10,
choices=FULL_STATUS,
default='u',
)
test_status = models.CharField(
max_length=10,
choices=STATUS,
default='u',
)
test_comment = models.TextField(max_length=200, blank=True)
decision_status = models.CharField(
max_length=10,
choices=FULL_STATUS,
default='u',
)
offer_status = models.CharField(
max_length=10,
choices=OFFER_STATUS,
default='u,'
)
internal_comment = models.TextField(max_length=200, blank=True)
created_at = models.DateTimeField(
editable=False,
null=True,
)
updated_by = models.CharField(max_length=30, editable=False, null=True)
Currently I'm using an approach that is mentioned in Django: When saving, how can you check if a field has changed? but with many variables this process become repetitive:
def __init__(self, *args, **kwargs):
super(Cv, self).__init__(*args, **kwargs)
#override original fields' values with current values
self.__original_schedule = self.schedule
self.__original_schedule_confirm = self.schedule_confirm
self.__original_name = self.name
self.__original_position = self.position
self.__original_team = self.team
self.__original_leader = self.leader
self.__original_email = self.email
self.__original_email_sent_status = self.email_sent_status
self.__original_phone = self.phone
#etc
def save(self, *args, **kwargs):
if self.__original_schedule != self.schedule:
#do something etc
I want to find a way to optimize this process. I have read somewhere that you can use #property to track variables' changes and I want to know if I can use this approach in my model. If not, is there any other way i can improve my method.
Why not django signals? see docs here
post_save signal is fired every time you save a model object.
Working example :
In your models.py add..
from django.db.models.signals import post_save
from django.dispatch import receiver
#receiver(post_save, sender=Cv)
def hear_signal(sender , instance , **kwargs):
if kwargs.get('created'):
return # if a new model object is created then return. You need to distinguish between a new object created and the one that just got updated.
#Do whatever you want.
#Your trigger function content.
#Parameter "instance" will have access to all the attributes of the model being saved. To quote from docs : It's "The actual instance being saved."
return
Thanks. Hope this helps.

Django limit_choices_to on OneToOneField with upstream ForeignKey field

I am trying to use the "limit_choices_to" functionality in a Django OneToOneField where upstream of what I want to limit the choices on is another ForeignKey. The error I get in the admin with the way I have it set up is:
invalid literal for int() with base 10: 'Storage Array'
I assume this is because it is looking at the actual value in the column asset_type which is an integer foreign key. I need to be able to limit the choices based on a field value of the foreign key as opposed to the key value itself.
Basically what I am trying to accomplish is having the admin area (and other forms) only allow you to choose a valid asset type when adding a new asset. For example, if I am adding a "storage array" the upstream asset tied to it should only be allowed to be asset_type of storage array.
Here is my model:
from django.db import models
from localflavor.us.us_states import STATE_CHOICES
# Table of brand names of assets
class Brand(models.Model):
brand = models.CharField(max_length=128, unique=True)
def __unicode__(self):
return self.brand
# Table of device types for assets, e.g. "Storage Array"
class Device(models.Model):
device_type = models.CharField(max_length=128, unique=True)
device_url_slug = models.SlugField(max_length=70, unique=True)
class Meta:
verbose_name = "device type"
verbose_name_plural = "device types"
def __unicode__(self):
return self.device_type
# Table of asset locations
class Location(models.Model):
site_name = models.CharField(max_length=128, unique=True)
site_nick = models.CharField(max_length=5, unique=True)
address_line_one = models.CharField(max_length=256)
address_line_two = models.CharField(max_length=256, null=True, blank=True)
address_city = models.CharField(max_length=32)
address_state = models.CharField(max_length=2, choices=STATE_CHOICES, null=True, blank=True)
address_zip = models.CharField(max_length=5)
def __unicode__(self):
return self.site_name
# Table of Environments, e.g. "Production"
class Environment(models.Model):
environment = models.CharField(max_length=128, unique=True)
def __unicode__(self):
return self.environment
class Credentials(models.Model):
AUTH_CHOICES = (
('SSH', 'Standard SSH'),
('SSH-Key', 'SSH with Key-based login'),
('HTTP', 'Standard HTTP'),
('HTTPS', 'Secure HTTP'),
('API', 'API Based'),
('SNMP', 'SNMP Based'),
)
SNMP_VERSIONS = (
('v1', 'SNMP v1'),
('v3', 'SNMP v3'),
)
auth_method = models.CharField(max_length=32, choices=AUTH_CHOICES)
auth_username = models.CharField(max_length=32)
auth_password = models.CharField(max_length=32, null=True, blank=True)
auth_snmp_version = models.CharField(max_length=2, choices=SNMP_VERSIONS, null=True, blank=True)
auth_snmp_community = models.CharField(max_length=128, null=True, blank=True)
class Meta:
verbose_name = "credentials"
verbose_name_plural = "credentials"
def __unicode__(self):
return self.auth_method
class Asset(models.Model):
asset_name = models.CharField(max_length=128, unique=True)
asset_type = models.ForeignKey(Device)
brand = models.ForeignKey(Brand)
model = models.CharField(max_length=128)
serial = models.CharField(max_length=256)
location = models.ForeignKey(Location)
environment = models.ForeignKey(Environment)
datacenter_room = models.CharField(max_length=32, null=True, blank=True)
grid_location = models.CharField(max_length=32, null=True, blank=True)
mgmt_address = models.CharField(max_length=128)
notes = models.TextField(null=True, blank=True)
def __unicode__(self):
return self.asset_name
class StorageArray(models.Model):
OS_NAME_CHOICES = (
('Data OnTap', 'NetApp Data OnTap'),
)
OS_TYPE_CHOICES = (
('7-Mode', 'NetApp 7-Mode'),
('cDOT', 'NetApp Clustered'),
)
HA_TYPE_CHOICES = (
('Standalone', 'Standalone System'),
('HA Pair', 'HA Pair'),
('Clustered', 'Clustered'),
)
asset = models.OneToOneField(Asset, primary_key=True, limit_choices_to={'asset_type': 'Storage Array'})
os_name = models.CharField(max_length=32, choices=OS_NAME_CHOICES, null=True, blank=True)
os_version = models.CharField(max_length=16, null=True, blank=True)
os_type = models.CharField(max_length=16, choices=OS_TYPE_CHOICES, null=True, blank=True)
array_ha_type = models.CharField(max_length=32, choices=HA_TYPE_CHOICES, null=True, blank=True)
array_partner = models.CharField(max_length=128, null=True, blank=True)
credentials = models.ForeignKey(Credentials, null=True, blank=True)
class Meta:
verbose_name = "storage array"
verbose_name_plural = "storage arrays"
def __unicode__(self):
return self.asset.asset_name
class SANSwitch(models.Model):
OS_NAME_CHOICES = (
('FabricOS', 'Brocade FabricOS'),
)
SWITCH_TYPE_CHOICES = (
('Standalone', 'Standalone Switch'),
('Director', 'Director'),
('Router', 'Multiprotocol Router'),
('Blade', 'Blade Chassis IO Module'),
)
SWITCH_ROLE_CHOICES = (
('Core', 'Core'),
('Edge', 'Edge'),
('AG', 'Access Gateway'),
)
asset = models.OneToOneField(Asset, primary_key=True, limit_choices_to={'asset_type': 'SAN Switch'})
os_name = models.CharField(max_length=32, choices=OS_NAME_CHOICES, null=True, blank=True)
os_version = models.CharField(max_length=16, null=True, blank=True)
switch_type = models.CharField(max_length=32, choices=SWITCH_TYPE_CHOICES, null=True, blank=True)
switch_role = models.CharField(max_length=32, choices=SWITCH_ROLE_CHOICES, null=True, blank=True)
credentials = models.ForeignKey(Credentials, null=True, blank=True)
class Meta:
verbose_name = "san switch"
verbose_name_plural = "san switches"
def __unicode__(self):
return self.asset.asset_name
I fixed it all by myself!
It seems to translate further down a relationship you can make use of the double underscore notation that python/django has built in.
To fix my issue:
asset = models.OneToOneField(Asset, primary_key=True, limit_choices_to={'asset_type': 'Storage Array'})
became:
asset = models.OneToOneField(Asset, primary_key=True, limit_choices_to={'asset_type__device_type': 'Storage Array'})

Categories