Django: IntegrityError when migrating after adding foreign key field - django

I have three models as follows in a Django app named markets:
class Market(models.Model):
title = models.CharField(max_length=50, default="")
current_price = models.DecimalField(max_digits=5, decimal_places=2, default=0.50)
description = models.TextField(default="")
shares_yes = models.IntegerField(default=0)
shares_no = models.IntegerField(default=0)
b = models.IntegerField(default=100)
cost_function = models.IntegerField(default=0)
open = models.BooleanField(default=True)
def __str__(self):
return self.title[:50]
def get_absolute_url(self):
return reverse('market_detail', args=[str(self.id)])
class Price(models.Model):
market = models.ForeignKey(
Market,
on_delete=models.CASCADE,
related_name='prices',
default=None)
price = models.DecimalField(
max_digits=5,
decimal_places=2,
default=0.50)
price_date = models.DateTimeField(
default=now,
blank=True)
def __str__(self):
return str(self.price)
def get_absolute_url(self):
return reverse('market_list')
class Share(models.Model):
user = models.ForeignKey('users.CustomUser',
on_delete=models.CASCADE,
related_name='user_shares',
default=None)
market = models.ForeignKey(
Market,
on_delete=models.CASCADE,
related_name='market_shares',
default=None)
share = models.IntegerField(default=0)
transaction_date = models.DateTimeField(
default=now,
blank=True)
def __str__(self):
return str(self.share)
def get_absolute_url(self):
return reverse('market_list')
I would like to add the following foreign key field to the Price model:
user = models.ForeignKey('users.CustomUser',
on_delete=models.CASCADE,
related_name='user_prices',
default=None)
When I run makemigrations on markets, there's no issue. But when I try to actually migrate the database, I get the following error:
django.db.utils.IntegrityError: column "user_id" contains null values
Why is that? I had no issues adding a user field to the Share model, so am not clear on why I run into problems when also looking to add it to Price.

When I run makemigrations on markets, there's no issue. But when I try
to actually migrate the database, I get the following error:
django.db.utils.IntegrityError: column "user_id" contains null values
Why is that?
A ForeignKey is by default non-NULLable. But you specify a default=None. The migraiton thus aims to insert NULL for the existing records, and that will fail.
You can make your ForeignKey nullable with:
user = models.ForeignKey('users.CustomUser',
on_delete=models.CASCADE,
related_name='user_prices',
null=True,
default=None
)
You will need to remove (or alter) the migration file, and recreate a migration file.
Another way to resolving this is providing a CustomUser object to which you link the existing records, with that user.
Note: usually it is better to use get_user_model() [Django-doc] instead of providing the user model as a reference or string. If you later change your mind, you can alter the setting, and then all ForeignKeys will be remapped on the new user model.

Related

Django - ForeignKey Filter Choices

I'd like to filter the choices that a user can choose in my ForeignKey Field.
I basically have a ForeignKey for the subject of the Test and the actual topic of the Test. These topics come from a different model and are linked to a subject. Now I'd like to filter the choices to only include the topics that are linked to the currently selected subject. Is that possible and if so, how?
models.py
class Test(models.Model):
student = models.ForeignKey(Person, on_delete=models.CASCADE, blank=True, null=True)
subject = models.ForeignKey(Subject, on_delete=models.CASCADE, blank=True, null=True)
thema = models.ForeignKey(Thema, on_delete=models.CASCADE, blank=True, null=True)
school_class = models.ForeignKey(SchoolClass, on_delete=models.CASCADE, blank=True, null=True)
grade = models.FloatField(validators=[MinValueValidator(0), MaxValueValidator(6)], blank=True, null=True)
date = models.DateField(default=datetime.date.today)
def save(self, *args, **kwargs):
if not self.school_class and self.student:
self.school_class = self.student.klasse
return super().save(*args, **kwargs)
class Thema(models.Model):
subject = models.ForeignKey(Subject, on_delete=models.CASCADE, blank=True, null=True)
thema = models.CharField(max_length=50)
class Subject(models.Model):
teacher = models.ForeignKey(Person, on_delete=models.CASCADE, blank=True, null=True)
name = models.CharField(max_length=20)
The Problem if I use this:
# thema model #staticmethod
def return_thema(subject):
themen = Thema.objects.filter(subject=subject)
return {'thema': themen}
#test model
thema = models.ForeignKey(Thema, on_delete=models.CASCADE, blank=True, null=True,limit_choices_to=Thema.return_thema(subject))
Is that I get the Error:
django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.
Meaning I can't get the objects of the Thema Model while the models are loading
EDIT (for Swift):
That seemed to resolve the error when trying to makemigrations, but I now get this error, when visiting the admin portal to create a new Test:
File "/Users/di/Code/Schule/GymnasiumApp/venv/lib/python3.10/site-packages/django/db/models/sql/query.py", line 1404, in build_filter
arg, value = filter_expr
ValueError: too many values to unpack (expected 2)
I think what you are looking for ideally would be ForeignKey.limit_choices_to
Please see the docs:
https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.limit_choices_to
You can limit the choices available at a model level, which is enforced throughout the django app, including forms automatically.
Edit because OP provided more information
Ok so I believe if you declare the thema field on the test model like so, it will solve the issue, and I will explain why after:
class Test(models.Model):
student = models.ForeignKey(Person, on_delete=models.CASCADE, blank=True, null=True)
subject = models.ForeignKey(Subject, on_delete=models.CASCADE, blank=True, null=True)
thema = models.ForeignKey(Thema, on_delete=models.CASCADE, blank=True, null=True, limit_choices_to=Q('thema_set__subject_set'))
school_class = models.ForeignKey(SchoolClass, on_delete=models.CASCADE, blank=True, null=True)
grade = models.FloatField(validators=[MinValueValidator(0), MaxValueValidator(6)], blank=True, null=True)
date = models.DateField(default=datetime.date.today)
def save(self, *args, **kwargs):
if not self.school_class and self.student:
self.school_class = self.student.klasse
return super().save(*args, **kwargs)
We are essentially telling Django to evaluate the relationship between the limited choices "lazily" I.e. when the form is loaded dynamically. Django forms will look at the limit_choices_to field argument and apply it to the available choices.
I'm not 100% about the relationship of your models so the Q(...) I added, might actually need to be Q('subject_set')
If you use django forms you can use the model choice field.
In your view you can set your queryset of this choicefield. Zo you can filter it.
fields['your model field'].queryset = yourmodel.objects.filter(your filter parameters)
I think there is also problem in save method also. Aren't you need to write the name of the model inside like
return super(<modelName>).save(*args, **kwargs)

IntegrityError: update or delete on table "products_product" violates foreign key constraint

I am trying to delete from Django admin all the products which are stored in PostgresSQL database but getting that error for one product:
IntegrityError at /admin/products/product/
update or delete on table "products_product" violates foreign key constraint "products_curateprodu_product_id_ec2cf1ec_fk_products_" on table "products_curateproducts_products"
DETAIL: Key (id)=(72) is still referenced from table "products_curateproducts_products".
I am not able to figure out why it shows that error while under Curranted Products in Django admin I don´t have any products. At least it won´t show there any, just 0 Curated Products.
Code is here for the Product model:
class Product(models.Model):
seller = models.ForeignKey(SellerAccount, on_delete=models.CASCADE)
media = models.ImageField(blank=True,
null=True,
upload_to=download_media_location,
storage=FileSystemStorage(location=settings.PROTECTED_ROOT))
title = models.CharField(max_length=150)
slug = models.SlugField(blank=True, unique=True)
description = models.TextField(max_length=200, null=True)
price = models.DecimalField(max_digits=10, decimal_places=2, default=9.99, null=True)
sale_active =models.BooleanField(default=False)
sale_price = models.DecimalField(max_digits=100, decimal_places=2, null=True, blank=True)
def __str__(self):
return self.title
class Meta:
verbose_name = 'Product'
verbose_name_plural = 'Products'
ordering = ['title']
and code for Curated Products model:
class CuratedProducts(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, blank=True)
section_name = models.CharField(max_length=20, null=True, blank=True)
products = models.ManyToManyField(Product, blank=True)
active = models.BooleanField(default=True)
def __str__(self):
return self.section_name
class Meta:
verbose_name = 'Curated Product'
verbose_name_plural = 'Curated Products'
Update, using:
Django 3.0.5,
psycopg2-binary 2.8.5
The error message is showing:
DETAIL: Key (id)=(72) is still referenced from table "products_curateproducts_products".
Note the name curateproducts_products. That does match the model you show. There is another table in the mix.

Django: How to generate unique order id

This is how my model looks like. When ever user orders. The order id provided by django is simple. Its like 1,2,3 ..... 100.
class UserOrder(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='orders',
on_delete=models.CASCADE)
cart = models.ForeignKey(Cart, related_name="orders", on_delete=models.CASCADE, null=True,
blank=True)
date = models.DateTimeField(default=datetime.now)
total_price = models.IntegerField(null=True, blank=True)
note = models.TextField(null=True, blank=True)
cancel_reason = models.TextField(null=True, blank=True)
cancelled = models.BooleanField(default=False)
confirmed = models.BooleanField(default=False)
def __str__(self):
return self.user.username
Your question is not well defined but I think I understand your problem, you need a id (lookup field) that is not simple.
you can use uuid, and use this uuid for all the lookup in the viewsets, instead of the sequentially created id by django.
something like this lookup_field = 'uuid' in views.
import uuid
class UserOrder(models.Model):
uuid = models.UUIDField(default=uuid.uuid4, unique=True, db_index=True, editable=False)
read more about uuids here https://docs.python.org/3/library/uuid.html#uuid.uuid4
try using the django-random-id-model
run pip install django-random-id-model
in your django models.py file import RandomIDModel from django-random-id-model
then add RandomIdModel to your model class, in case this is:
class UserOrder(RandomIdModel):
#remaining codes here

Foreign key not being recognized

I've created two models. When I run makemigrations, I'm getting the following error:
ERRORS:
userorders.UserCartItem: (fields.E336) The model is used as an intermediate model by 'userorders.UserCart.items', but it does not have a foreign key to 'UserCart' or 'UserService'.
models.py
class UserCartItem(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, default=None)
cart = models.ForeignKey("UserCart", on_delete=models.CASCADE)
quantity = models.PositiveIntegerField(default=1)
line_item_total = models.DecimalField(max_digits=10, decimal_places=2)
def __str__(self):
return str(self.id)
class UserCart(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, default=None)
items = models.ManyToManyField(UserService, through=UserCartItem)
items_total = models.DecimalField(max_digits=50, decimal_places=2, default=0.00)
def __str__(self):
return str(self.id)
Any thoughts on what the problem is? I've defined the foreign key on UserCartItem as UserCart, but it looks like it's not being recognized. I should point out that I understand that when you identify another model as a foreign key and the foreign key model is below the model that you are working in, you have to put the foreign key model in quotation marks, hence why I used quotation marks in this line:
models.ForeignKey("UserCart", on_delete=models.CASCADE)
thanks!
Had to add default=None:
models.ForeignKey("UserCart", on_delete=models.CASCADE, default=None)

Django migrations Many2Many Through model, ValueError: Cannot alter field

Hey guys I want to sort my many to many field and in that case I want to through. My code look something like this:
class SkirunRatePoint(models.Model):
latitude = models.DecimalField(u'lat', max_digits=10, decimal_places=6)
longitude = models.DecimalField(u'lng', max_digits=10, decimal_places=6)
elevation = models.DecimalField(max_digits=10, decimal_places=6, blank=True, null=True)
name = models.CharField(u'Name', max_length=200, blank=True, null=True)
class Meta:
verbose_name = u'Point'
verbose_name_plural = u'Points'
def __unicode__(self):
return unicode('{0} / {1}'.format(self.latitude, self.longitude))
class SkirunRoute(models.Model):
skirun = models.ForeignKey(Skirun, verbose_name=u'Path')
ratepoints = models.ManyToManyField(
SkirunRatePoint,
through="SkirunRatePointThrough",
verbose_name=u'Points',
blank=True,
)
class Meta:
verbose_name_plural = u'trasy z punktami'
def __unicode__(self):
return unicode(self.skirun)
class SkirunRatePointThrough(models.Model):
skirunroute = models.ForeignKey(SkirunRoute, related_name="skirun_route")
skirunratepoint = models.ForeignKey(SkirunRatePoint, related_name="skirun_rate_points")
order = models.IntegerField(
blank=True,
null=True,
)
Don't mind about indents, they are find on my pc.
Makemigrations is going fine, but when I try to migrate it throws me an error which says:
ValueError: Cannot alter field skirun.SkirunRoute.ratepoints into skirun.SkirunRoute.ratepoints - they are not compatible types (you cannot alter to or from M2M fields, or add or remove through= on M2M fields)
Any ideas what might be the problem ?