Django ForeignKey value does not have corresponding value - django

I'm working on the Django section of CS50 around the 30min mark on the video with the modes 'ForeignKey' section.
When i run the make migration i get the error.
You are trying to add a non-nullable field 'agent' to product without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Quit, and let me add a default in models.py
Select an option: 2
if I set the default as a string value i get the error saying it was expecting an id.
If i set it as 1 then i get the following.
The row in table 'clutter_product' with primary key '1' has an invalid foreign key: clutter_product.agent_id contains a value '1' that does not have a corresponding value in clutter_supplier.id.
class Supplier(models.Model):
company = models.CharField(max_length=64)
contact = models.CharField(max_length=64)
email = models.CharField(max_length=128, blank = True)
def __str__(self):
return f"{self.id} {self.company} {self.contact} {self.email}"
class Product(models.Model):
name = models.CharField(max_length=64)
sku = models.CharField(max_length=64, blank = True)
unit_cost = models.IntegerField()
rrp = models.IntegerField()
average_fee = models.IntegerField()
shipping_fee = models.IntegerField()
agent = models.ForeignKey(Supplier, default=1, on_delete=models.CASCADE, related_name="suppliers")

I would suggest to try these steps:
First, delete the migration file which is causing this problem.
Second change the model like this:
class Product(models.Model):
# rest of the fields
agent = models.ForeignKey(Supplier, null=True, default=None, on_delete=models.CASCADE, related_name="suppliers")
Third run makemigrations and migrate.
Fourth create a instance of supplier using supplier = Supplier.objects.create(company="ABC", contact="contact", email="a#b.c", pk=1)
Fifth(optional) Update the existing Product to haven a supplier-Product.objects.update(agent=supplier).
Sixth, if you want to constrain Products to be created with an agent, then remove null=True, default=None from agent field in Product model. Then run makemigrations and migrate.

Related

Test a data migration ManyToMany in Django

I tried to add a field to my ManyToMany relationship models in Django.
So step by step, I created the new model and apply makemigrations and migrate.
I checked I have the new table in my postgresql database.
Now before I will add the through keyword in the ManyToMany field I want to write a function in the migration file that will copy the old data of the previous ManyToMany table to the new one with the additional field.
I followed a solution explained here:
Django migration error :you cannot alter to or from M2M fields, or add or remove through= on M2M fields
I want to test the function that will migrate the data in a test function but I don't understand what to do.
here my code:
survey/models:
class Survey(BaseModel):
name = models.CharField(max_length=256, help_text='Survey name')
user = models.ManyToManyField(User, blank=True, help_text='patient')
survey/models:
class SurveyStatus(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
survey = models.ForeignKey(Survey, on_delete=models.CASCADE)
survey_status = models.CharField(max_length=10,
blank=True,
null=True,
choices=STATUS_SURVEY_CHOICES,
)
The function I wrote that need to copy the data from the previous M2M to the new one is the following one:
def create_through_relations(apps, schema_editor):
Survey = apps.get_model('survey', 'Survey')
SurveyStatus = apps.get_model('survey', 'SurveyStatus')
for survey in Survey.objects.all():
for user in survey.user.all():
SurveyStatus(
user=user,
survey=survey,
survey_status='active'
).save()
I don't understand what is apps? because it is not recognized by python
I don't understand why i need schema_editor because it's not used
it doesn't recognized my Survey or SurveyStatus models too
when i tried to run this script with
if __name__ == "__main__":
create_through_relations(survey)
I've got this error
NameError: name 'survey' is not defined
and if i tried this function
from django.apps import apps
def create_through_relations():
Survey = apps.get_model('survey', 'Survey')
SurveyStatus = apps.get_model('survey', 'SurveyStatus')
for survey in Survey.objects.all():
for user in survey.user.all():
SurveyStatus(
user=user,
survey=survey,
survey_status='active'
).save()
when i tried to run this script with
if __name__ == "__main__":
create_through_relations()
I've got this error
django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.
If someone can help and explain me how to solve.thanks
1: Apps represent the different parts of your project (Django Apps)
2: You don't need it at this point. In general, it translates the models into SQL syntax.
3: python manage.py <...> does load the models for execution. Your file is trying to access data that isn't available that way.
4: The variable survey can't be found in python's main function, since you never declared it there. You need to trigger it inside your project.
5: You can test things by creating a test.py (Django Tests)
6: You don't need to transfer the data to a whole new table after changing a model, just extend the existing one and migrate the changes:
class BaseModel(models.Model):
created = models.DateTimeField('created', default=timezone.now)
changed = models.DateTimeField('changed', default=timezone.now, blank=True, null=True)
class Survey(BaseModel):
uuid = models.UUIDField(primary_key=False, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=256, help_text='Survey name')
description = models.TextField('description', blank=True)
status = models.BooleanField(default=False) # paused/ active
class SurveyQuestion(BaseModel):
survey = models.ForeignKey(Survey, related_name='survey', on_delete=models.CASCADE)
text = models.CharField(max_length=256)
# 1 -> Text, # Integer, # ChoiceField, etc.
requested_result = models.IntegerField(default=0)
class QuestionResult(BaseModel):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
question = models.ForeignKey(SurveyQuestion, related_name='survey_question', on_delete=models.CASCADE)
answer = models.CharField(default='', max_length=256)

Django thinks I have an id field when I do not

I have created the following model:
class World(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
name = models.CharField(max_length=200)
setting = models.CharField(max_length=200)
creation_date = models.DateTimeField('date created')
when I run manage.py makemigrations I get the following error:
You are trying to add a non-nullable field 'id' to world without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Quit, and let me add a default in models.py
Why does Django think I have an id field, and how do I get rid of this error?
I had previously set an ID field in my World model, this was confusing something as I had deleted it, I have added the line:
id = models.AutoField(primary_key=True)
When i ran makemitigrations again it asked me if I had renamed the ID field to this new one and I clicked yes and this sorted it out.
My model is now:
class World(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, default='')
name = models.CharField(max_length=200)
setting = models.CharField(max_length=200)
creation_date = models.DateTimeField('date created')

Django: How can I add/delete fields in sqlite3 database?

I've started learning Django from a YouTube course.
In the models.py file, there are two classes.
class Album(models.Model):
artist = models.CharField(max_length = 250)
album_title = models.CharField(max_length = 250)
album_logo = models.CharField(max_length = 1000)
def __str__(self):
return self.album_title + ' - ' + self.artist
class Song(models.Model):
album = models.ForeignKey(Album, on_delete=models.CASCADE)
file_type = models.CharField(max_length=10)
song_title = models.CharField(max_length=250)
genre = models.CharField(max_length=250)
def __str__(self):
return self.song_title
I added the genre in the Song after the migration. That's why I'm having problem while adding data.
In the interactive shell, if I try to save() , it shows there's no 'genre' field. If I try to migrate again, it shows something like this:
You are trying to add a non-nullable field 'genre' to song without a
default; we can't do that (the database needs something to populate
existing rows). Please select a fix:
1) Provide a one-off default now
(will be set on all existing rows with a null value for this column)
2) Quit, and let me add a default in models.py Select an option:
What's the proper way of adding or deleting fields?
add default="" to genere field
class Song(models.Model):
album = models.ForeignKey(Album, on_delete=models.CASCADE)
file_type = models.CharField(max_length=10)
song_title = models.CharField(max_length=250)
genre = models.CharField(max_length=250, default="")
def __str__(self):
return self.song_title
As the error message shows, you add a field genre to Song model without adding default="" nor null=True parameters to it. When you migrate it, django don't know how to deal with the old data that has been inserted into the database without genere field. So you should set them to null with null=True or other default value with default="".
You can also just keep your code. But when you use the migrate command, you should tell django that you will give a default value like the django recommanded:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
press 1 and enter key. input "" and then django will set all the old data genre="".

How to save a table entry in django

I am working on a django admin based project now i am stuck with a big thing.i want to add a field named "item_issued" in the user_profile model.
in the "item issued" field there is a table which consist of 3 column "item_name","quantity" and "price".I am unable to apply this.Can u guys please help me in this?
Thanks in advance
If I understand you correctly you want to add a ForeignKey to your user_profile pointing to item_issued. You can accomplish that by creating a new model ItemIssued with the fields you mentioned:
class ItemIssued(models.Model):
item_name = models.CharField(max_length=100)
quantity = models.IntegerField()
price = models.FloatField()
Now, when you're having ItemIssued model you can add a ForeignKey to user_profile (I assume the model is called UserProfile):
class UserProfile(models.Model):
... # your existing fields
item_issued = models.ForeignKey(ItemIssued)
After that, don't forget to run
python manage.py makemigrations app
python manage.py migrate
Here is a starting point:
models.py:
class ItemIssued(models.Model):
item_name = models.CharField(max_length=50)
quantity = models.IntegerField()
models.DecimalField(max_digits=6, decimal_places=2) #use decimal field for price values.
class UserProfile(models.Model):
# some other fields..
issued_items = models.ManyToManyField("ItemIssued", related_name="+issued_items", null=True, blank=True)
And if you need to use this field outside of Django Admin, views.py:
user = UserProfile.objects.get(username="ali")
new_issued_item = ItemIssued.objects.get(item_name="test_item")
user.issued_items.add(new_issued_item) #add
user.issued_items.delete(new_issued_item) #delete
items = user.issued_items.all() # get all issued items of user
i didn't test the code. But they should work.

Django postions: adding PositionField breaking migration

I have already tables for Vehicle and Car, Using this django-positions for postioning my items of the tables. For that i have added the positon field in both the models.
class Vehicle(models.Model):
name = models.CharField(max_length=50)
slug = models.SlugField(max_length=50, unique=True)
position = PositionField()
And
class Car(models.Model):
name = models.CharField(max_length=50)
slug = models.SlugField(max_length=50, unique=True)
vehicle = models.ForeignKey(Vehicle, related_name="vehicle")
position = PositionField()
makemigrations ran fine but while migrate getting following error. using postgreSQL
django.db.utils.IntegrityError: check constraint "myapp_vehicle_position_check" is violated by some row
It turns out that during the migration the SQL code checks for the value of the PositionField to be greater than or equal to 0. The default being -1 for automatic ordering the migration fails.
I haven't digged any more but as a turnaround changing the default value to something equal or above zero allow for the migration to be successful.
class Vehicle(models.Model):
name = models.CharField(max_length=50)
slug = models.SlugField(max_length=50, unique=True)
position = PositionField(default=99)
Hope this helps.