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
Related
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'),
)
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.
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,
)
I expect to receive a var contact_exists that I can use to update some fields. However, the following query always gives me back django.core.exceptions.FieldError: Related Field got invalid lookup: event
Do you have any idea why event_related_fields__event doesn't work the way I expected?
for selected_order in Order.objects.all():
contact_exists = Contact.objects.filter(
event_related_fields__event=selected_order.event,
)
Here my models.py:
class Contact(TimeStampedModel):
consent = models.BooleanField(verbose_name=_("Consent"))
email = models.EmailField(verbose_name=_("Your email"))
first_name = models.CharField(
max_length=100, # TODO Length must be same as for billing model
verbose_name=_("First name"),
null=True,
blank=True,
)
last_name = models.CharField(
max_length=100, # TODO Length must be same as for billing model
verbose_name=_("Last name"),
null=True,
blank=True,
)
events = models.ManyToManyField(Event, related_name='contacts')
event_related_fields = models.ManyToManyField(
Event, related_name='event_related_fields', through='EventRelatedFields'
)
organizer = models.ForeignKey(
Organizer, on_delete=models.PROTECT, related_name='contacts'
) # PROTECT = don't allow to delete the organizer if contact exists
class Meta:
verbose_name = _("Contact")
verbose_name_plural = _("Contacts")
ordering = ('created',)
unique_together = ('email', 'organizer')
def __repr__(self):
return "{}: {}".format(self.__class__.__name__, self)
def __str__(self):
return self.email
class EventRelatedFields(TimeStampedModel):
event = models.ForeignKey(Event, on_delete=models.CASCADE)
contact = models.ForeignKey(Contact, on_delete=models.CASCADE)
lead = models.BooleanField(
verbose_name='Lead', default=False
) # Contact who 'Signed Up'
attendee = models.BooleanField(
verbose_name='Attendee', default=False
) # Contact assigned to ticket
purchaser = models.BooleanField(
verbose_name='Purchaser', default=False
) # Contact made the order
class Meta:
unique_together = [['event', 'contact']]
You don't need the __event lookup, try using:
for selected_order in Order.objects.all():
contact_exists = Contact.objects.filter(
event_related_fields=selected_order.event,
)
The lookup part should contain field names of Event model.
In my models.py I filter for two cases. I check if there is:
a ticket_on_sale
ticket_on_sale_soon
If 2) is given but 1) not, then the method should give back True. I filter on a variable level (after the database is already hit). I wonder if there is a more solid way. What I did doesn't feel right. Do you have suggestions?
models.py
class Event(TimeStampedModel):
organizer = models.ForeignKey(
Organizer,
on_delete=models.PROTECT,
related_name='events',
) # PROTECT = don't allow to delete the organizer if an event exists
name = models.CharField(
max_length=50,
verbose_name=_("Event Title"),
)
slug = models.SlugField(
validators=[SlugBlackList()],
verbose_name=_("Event Link"),
)
currency = models.CharField(
max_length=10,
choices=CURRENCY_CHOICES,
verbose_name=_("Currency"),
)
status = models.CharField(
max_length=8,
choices=EventStatus.CHOICES,
default=EventStatus.DRAFT,
verbose_name=_("Status"),
)
venue_address = models.TextField(
null=True,
blank=True,
verbose_name=_("Location address"),
)
start_date = models.DateTimeField(verbose_name=_("Start date"))
end_date = models.DateTimeField(verbose_name=_("End date"))
#cached_property
def only_scheduled_tickets(self):
tickets = self.tickets.all()
ticket_on_sale = list(filter(
lambda ticket: ticket.is_on_sale() and ticket.is_available(),
tickets,
))
ticket_on_sale_soon = list(filter(
lambda ticket: ticket.is_on_sale() and not ticket.is_available(),
tickets,
))
if ticket_on_sale_soon and not ticket_on_sale:
return True
class Ticket(TimeStampedModel):
event = models.ForeignKey(
Event,
on_delete=models.CASCADE,
related_name='tickets',
) # CASCADE = delete the ticket if the event is deleted
tax = models.ForeignKey(
'Tax',
on_delete=models.PROTECT,
related_name='tickets',
blank=True,
null=True,
) # PROTECT = don't allow to delete the ticket tax if a ticket exists
name = models.CharField(
max_length=100,
verbose_name=_("Ticket Name"),
)
price_gross = models.PositiveIntegerField(
verbose_name=_("Price gross"),
)
description = models.TextField(
null=True,
blank=True,
)
start_at = models.DateTimeField(
null=True,
blank=True,
verbose_name=_("Ticket sale starts at"),
)
end_at = models.DateTimeField(
null=True,
blank=True,
verbose_name=_("Ticket sale ends at"),
)
quantity = models.PositiveIntegerField(
verbose_name=_("Quantity"),
)
status = models.CharField(
max_length=8,
choices=TicketStatus.CHOICES,
default=TicketStatus.ON_SALE,
verbose_name=_("Status"),
)
In order to get the on_sale_soon field on your TicketQuerySet, you might need annotation such as
from datetime import date
from django.db import models
from django.db.models import Q, Value
tickets = Ticket.objects.annotate(
on_sale_soon=Case(
When(start_at__lte=date.today() + datetime.timedelta(days=10), then=Value(True, models.BooleanField())),
default=Value(False, models.BooleanField()),
output_field=models.BooleanField()
)
)
)
Afterwards, if you want to get tickets that are on sale soon, but not yet, you can do
tickets = tickets.objects.exclude(status=TicketStatus.ON_SALE)
tickets = tickets.filter(on_sale_soon=True)
Advantage of this is that everything will be done on the DB server in a single query.