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
Related
Currently im working on an Ecommerce project in Django where i have a Order model which has Foreign key relation with Product. So all the product details are fetched from product model. Now im facing issue with the same. Whenever I make any change to Product object its getting updated in all the related Order objects too even for orders placed in past.
Is it possible to keep past order's product values unchanged whenever Product object is updated in future? Please help. Below are the codes for your reference.
Product Model
class Product(models.Model):
measurement_choices = (('Liter', 'Liter'), ('Kilogram', 'Kilogram'), ('Cloth', 'Cloth'),
('Shoe', 'Shoe'))
name = models.CharField(max_length=200)
sku = models.CharField(max_length=30, null=True)
stock = models.CharField(max_length=10, null=True)
measurement = models.CharField(choices=measurement_choices, max_length=20, null=True)
description = models.CharField(max_length=10000)
price = models.DecimalField(max_digits=7, decimal_places=2)
discounted_price = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True)
image = models.ImageField(upload_to='product/images', default='product.png', null=True,
blank=True)
image_one = models.ImageField(upload_to='product/images', null=True, blank=True)
image_two = models.ImageField(upload_to='product/images', null=True, blank=True)
image_three = models.ImageField(upload_to='product/images', null=True, blank=True)
image_four = models.ImageField(upload_to='product/images', null=True, blank=True)
image_five = models.ImageField(upload_to='product/images', null=True, blank=True)
tags = models.ManyToManyField(Tags)
category = models.ForeignKey(Category,on_delete=models.SET_NULL,null=True,blank=True)
sub_category = models.ForeignKey(SubCategory, on_delete=models.SET_NULL,
null=True,related_name='+')
status = models.CharField(max_length=20, choices=(('Active', 'Active'), ('Inactive',
'Inactive')))
brand = models.ForeignKey(Brand,on_delete=models.PROTECT,blank=True, null=True)
offer = models.ForeignKey(Offer, on_delete=models.CASCADE, null=True, blank=True)
color = models.ForeignKey(Color , blank=True, null=True , on_delete=models.PROTECT)
size_type = models.ForeignKey(Size , blank=True, null=True , on_delete=models.PROTECT)
history = HistoricalRecords()
Order Model
class Order(models.Model):
order_status = (('Pending', 'Pending'), ('Under Process', 'Under Process'), ('Dispatched',
'Dispatched'),
('Delivered', 'Delivered'), ('Cancelled', 'Cancelled'), ('Out for delivery',
'Out for delivery'))
customer = models.ForeignKey(Customer, on_delete=models.SET_NULL, null=True, blank=True)
shipping_address = models.ForeignKey(ShippingAddress, on_delete=models.DO_NOTHING, null=True,
blank=True)
order_created = models.DateTimeField(auto_now_add=True,null=True)
date_ordered = models.DateTimeField(null=True)
complete = models.BooleanField(default=False)
transaction_id = models.CharField(max_length=100, null=True)
order_number = models.CharField(max_length=20, unique=True, null=True)
status = models.CharField(choices=order_status, default='Pending', max_length=30)
payment_status = models.CharField(choices=(('Received', 'Received'), ('Failed', 'Failed'),
('Pending', 'Pending')),
default='Pending', max_length=30)
ip_address = models.CharField(max_length=30, null=True)
# Payment details captured from payment gateway
payment_order_id = models.CharField(max_length=100, null=True) # razorpay order id
payment_id = models.CharField(max_length=100, null=True) # Razorpay payment id
payment_signature = models.CharField(max_length=100, null=True)# razorpay paymnet signature
payment_method = models.CharField(max_length=100, null=True)
history = HistoricalRecords()
I think there are a few options for you here if I understand your question correctly.
Either you can serialize the actual product details when saving the order. This could be done by using Django serialization and then storing this serialized product on the order with a JSONField. This way you'll keep the state for a product if you want to display or use the data later.
Another way would be to store a new product with a version ID, instead of updating your old products. This could be done by hooking on the pre save, creating a new version and blocking the saving of the old model. This way you'll store and can reuse the model in your templates. https://docs.djangoproject.com/en/3.2/topics/signals/
The last idea would be to use a historical model insert, such as django-simple-history. This would handle changes and updates for you, but you'll have to relate to a given history instance.
I am designing django models for a E-commerce market place site where user can buy 4 type of products . Like I have 4 type of diff models for them .
For clothes
class Merchandise(models.Model):
adOwner = models.ForeignKey(VendorProfile, on_delete=models.CASCADE)
imagesMerchandise = models.ManyToManyField(merchandiseImages)
productName = models.CharField(max_length=50, null=False, blank=False)
price = models.IntegerField()
availableQuality=models.IntegerField()
color=models.CharField(max_length=20, null=False, blank=False)
size = models.CharField(max_length=50 , null=False , blank=False)
description=models.CharField(max_length=250 , null=False , blank=False)
is_approved = models.BooleanField(default=False)
def __str__(self):
return str(self.productName)
for Rent a Car
class Vehicle(models.Model):
adOwner=models.ForeignKey(VendorProfile, on_delete=models.CASCADE)
carImages=models.ManyToManyField(Image)
make=models.CharField(max_length=50, null=False, blank=False)
modelName=models.CharField(max_length=50, null=False, blank=False)
registrationNumber=models.CharField(max_length=50, null=False, blank=False)
modelYear=models.CharField(max_length=50, null=False, blank=False)
modelColor=models.CharField(max_length=50, null=False, blank=False)
carType=models.CharField(max_length=50, null=False, blank=False)
fuelMileage=models.CharField(max_length=50, null=False, blank=False)
SeatingCapacity=models.CharField(max_length=50, null=False, blank=False)
vehicleCondition=models.CharField(max_length=50, null=False, blank=False)
fuelType=models.CharField(max_length=50, null=False, blank=False)
price=models.CharField(max_length=50, null=False, blank=False)
description=models.CharField(max_length=500, null=True, blank=True)
registerIn=models.CharField(max_length=500, null=True, blank=True)
is_approved = models.BooleanField(default=False)
def __str__(self):
return str(self.modelName)
book a hotel
class Accommodation(models.Model):
adOwner = models.ForeignKey(VendorProfile, on_delete=models.CASCADE)
hotleImages = models.ManyToManyField(HotleImages)
accommodationTitle=models.CharField(max_length=150)
location = models.CharField(max_length=150)
accommodationName = models.CharField(max_length=150)
checkIn = models.TimeField()
checkOut = models.TimeField()
# accessibility = models.CharField(max_length=20, null=False, blank=False)
address = models.CharField(max_length=150)
pets = models.CharField(max_length=150)
child = models.CharField(max_length=150)
is_approved = models.BooleanField(default=False)
Create a Activity
class ActivityOrganizer(models.Model):
adOwner = models.ForeignKey(VendorProfile, on_delete=models.CASCADE)
activityImage = models.ManyToManyField(ActivityImage)
activityName = models.CharField(max_length=50 , null=False, blank=False)
activityId = models.CharField(max_length=20, null=False, blank=False)
ageSuggestion = models.CharField(max_length=20, null=True, blank=True)
duration = models.CharField(max_length=20, null=False, blank=False)
openTime = models.TimeField()
closeTime=models.TimeField()
expiryDate = models.DateField()
availableQty = models.IntegerField()
price = models.IntegerField()
needToBring = models.CharField(max_length=50 , null=True , blank=True)
personsAllowOnOneTicket = models.IntegerField()
location = models.CharField(max_length=50 , null=True , blank=False)
specialNotes = models.CharField(max_length=250 ,null=True , blank=True)
description = models.CharField(max_length=250 , null=True , blank=True)
is_approved = models.BooleanField(default=False)
Now I made a order Table like this
class Orders(models.Model):
order_number = models.AutoField(primary_key=True)
total_amount = models.DecimalField(max_digits=10, decimal_places=2)
ordertime = models.DateTimeField(auto_now_add=True)
user_note=models.CharField(max_length=150 , null=True, blank=True)
address=models.CharField(max_length=150 , null=True, blank=True)
order_status = models.CharField(choices=STATUS , max_length=50)
payment_status=models.BooleanField(default=0)
Now I am confuse how to bind all these 4 categories to my order object. as If its a for single category I can simply create a foreign key with order model. But How can I bind all these (as user can pick 1,2,3,4 number of categories ) so if user select Accommodation , and Vehicle categories products how I can save 2 categories null in foreign key. Any help would be highly appreciated . thanks
If you have small number of products (4 in your case) and for each order only one item of a type can be ordered, then you can simply add those to the Orders model with nullable fields
class Orders(models.Model):
order_number = models.AutoField(primary_key=True)
total_amount = models.DecimalField(max_digits=10, decimal_places=2)
ordertime = models.DateTimeField(auto_now_add=True)
user_note=models.CharField(max_length=150 , null=True, blank=True)
address=models.CharField(max_length=150 , null=True, blank=True)
order_status = models.CharField(choices=STATUS , max_length=50)
payment_status=models.BooleanField(default=0)
merchandise = models.ForeignKey(Merchandise, on_delete=models.CASCADE, null=True, blank=True)
vehicle = models.ForeignKey(Vehicle, on_delete=models.CASCADE, null=True, blank=True)
accommodation = models.ForeignKey(Accommodation, on_delete=models.CASCADE, null=True, blank=True)
activity_organizer = models.ForeignKey(ActivityOrganizer, on_delete=models.CASCADE, null=True, blank=True)
To list all the orders of a specific category, exclude all the orders with null in given field.
Orders.objects.exclude(merchandise__isnull=True)
Also if only a single category product is ordered rest 3 fields will be null, if you want to enforce that business logic then you can check for it by creating a signal.
I am currently working on django. I created 4 classes in models.py, one of them is ReactionMeta class. This class has 62 columns, which defined as below:
class Reactionsmeta(models.Model):
id = models.ForeignKey('Reactions', db_column='id', primary_key=True, max_length=255, on_delete=models.CASCADE)
name = models.CharField(max_length=255, blank=True, null=True)
metabolite1 = models.ForeignKey('Metabolites', db_column='metabolite1', blank=True, null=True,
on_delete=models.CASCADE)
stoichiometry1 = models.CharField(max_length=255, blank=True, null=True)
metabolite2 = models.ForeignKey('Metabolites', db_column='metabolite2', blank=True, null=True,
on_delete=models.CASCADE, related_name='+')
stoichiometry2 = models.CharField(max_length=255, blank=True, null=True)
metabolite3 = models.ForeignKey('Metabolites', db_column='metabolite3', blank=True, null=True,
on_delete=models.CASCADE, related_name='+')
stoichiometry3 = models.CharField(max_length=255, blank=True, null=True)
metabolite4 = models.ForeignKey('Metabolites', db_column='metabolite4', blank=True, null=True,
on_delete=models.CASCADE, related_name='+')
#...
Some of the reactions, may have 6 metabolites, however, some of reactions may only have 2 metabolites and stoichiometries, which means there is no value of this reaction in metabolite3,4,5,6...columns and stoichiometry 3,4,5,6...columns.
In that case, how can I only display the Charfield with data while undisplay those Charfield with no value in django-admin?
So I think there is model design issue here. For my case i would have done this as follows
class ReactionMeta(models.Model):
reaction = models.ForeignKey(Reaction, ..)
name = models.CharField(..)
data = models.ForeignKey(Data, ..)
Contructing the Data class to hold the Stoichiometry and Metabolite
class Data(models.Model):
stoichiometry = models.CharField(..)
metabolite = models.ForeignKey(..)
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()
I have a form where I can create and edit a group (a business really). Though I want to be able to say this business has many locations. I have the models written but the UI is giving me trouble.
I think mostly my question would be answered by how to update the Group model (creating/editing a group) and the GroupLocations model with a single form (adding an address as a new location if need be) so almost three models with a single form?
The models are:
class Address(models.Model):
city = models.CharField(max_length=50)
state = models.CharField(max_length=50)
zip_code = models.CharField(max_length=50)
address_line_one = models.CharField(max_length=50)
address_line_two = models.CharField(max_length=50, null=True, blank=True)
contact = models.CharField(max_length=50, null=True, blank=True)
phone = models.CharField(max_length=50)
fax = models.CharField(max_length=50, null=True, blank=True)
created_at=models.DateField(auto_now_add=True)
updated_at=models.DateField(auto_now=True)
def __str__(self):
return self.city
class Group(models.Model):
group_name = models.CharField(max_length=50)
group_contact= models.CharField(max_length=50)
tin = models.CharField(max_length=50)
npi =models.CharField(max_length=50)
notes = models.TextField(max_length = 255, null=True, blank=True)
billing_address = models.ForeignKey('Address', related_name = 'billing_address', on_delete=models.SET_NULL, null=True)
mailing_address = models.ForeignKey('Address', related_name = 'mailing_address', on_delete=models.SET_NULL, null=True, blank=True)
start_date = models.DateField(auto_now=False, auto_now_add=False, null=True, blank=True)
end_date = models.DateField(auto_now=False, auto_now_add=False, null=True, blank=True)
change_date = models.DateField(auto_now=False, auto_now_add=False, null=True, blank=True)
change_text = models.TextField(max_length = 255, null=True, blank=True)
term_comment = models.TextField(max_length = 255, null=True, blank=True)
group_phone=models.CharField(max_length=50)
group_fax = models.CharField(max_length=50)
group_term = models.ForeignKey(GroupTerm, on_delete=models.SET_NULL, null=True, blank=True) #quesiton is can a group be termed many times?
created_at=models.DateField(auto_now_add=True)
updated_at=models.DateField(auto_now=True)
#provider_location = models.ManyToManyField('ProviderLocations', through='GroupLocations')
def __str__(self):
return self.group_name
class GroupLocations(models.Model):
address = models.ForeignKey('Address', on_delete= models.SET_NULL, null=True)
group = models.ForeignKey('Group', on_delete=models.CASCADE)
doing_business_as = models.CharField(max_length = 255)
created_at=models.DateField(auto_now_add=True)
updated_at=models.DateField(auto_now=True)
def __str__(self):
return self.doing_business_as
I would love to (for this model and others) mimic how the admin handles users with the nice left and right multiple select boxes: (Though not sure how the add new location maybe a button to take you to another form that somehow knows its supposed to be added to the group as well?)
I realize this is a very large question I am looking for just mostly I think how to deal with several models on one form/template rails had a word for this (the name escapes me now) and not sure what the Django paradigm is.