makemigrations does not create the trough model - django

I have made changes to one of my models in my project and migrate, makemigrations does not work as expected. Rebuilding the database creates only 2 out of 3 tables from my models.py and i cannot figure out the problem.
There are two different apps; "blog" and "users". both are registered in the setting.py.
I completely removed the database and deleted the migrations folders.
then i tried the following stuff:
django makemigrations blog
django migrate blog
doing a global django makemigrations does not have any effect, no changes are detected.
here is the relevant models.py of "blog":
class Room(models.Model):
roomname = models.CharField(max_length=6, unique=True)
roomeditors=models.ManyToManyField(User,related_name='rooms_user_can_edit', blank=True)
displayadmin=models.ForeignKey(User,
related_name='room_user_is_displayadmin',null=True, on_delete=models.SET_NULL)
def __str__(self):
return self.roomname
class Post(models.Model):
title = models.CharField(max_length=40)
content = models.TextField(max_length=300)
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
rooms = models.ManyToManyField(Room, related_name='roomposts', through='Display')
def __str__(self):
return self.title
def get_absolute_url(self):
return "/post/{}/".format(self.pk)
class Display(models.Model):
class Meta:
auto_created = True
post = models.ForeignKey(Post, on_delete=models.CASCADE)
room = models.ForeignKey(Room, on_delete=models.CASCADE)
isdisplayed = models.BooleanField(default=0)
def __str__(self):
return str(self.isdisplayed)
every table gets created except from display. the output is:
Migrations for 'blog':
blog\migrations\0001_initial.py
- Create model Room
- Create model Post

You are giving auto_created = True in your model's Meta class, which is not recommended neither its documented. Here is the list of all possible meta options you can give inside your model.
Official documentation says:
auto_created: Boolean flag that indicates if the field was automatically created, such as the OneToOneField used by model inheritance.
Giving this in Meta refrains Django to create this model itself.

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 no such column even after migrations

This is my model code
class Poll(models.Model):
created_at = models.DateTimeField(auto_now=True)
edited_at = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=200,default="X vs Y")
description = models.CharField(max_length=200,default="A poll")
def __str__(self):
return self.title
class Item(models.Model):
poll = models.ForeignKey('Poll',on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now=True)
edited_at = models.DateTimeField(auto_now_add=True)
name = models.CharField(max_length=200)
type_of = models.CharField(max_length=200)
description = models.TextField(max_length=1200)
votes = models.IntegerField(default=0)
def __str__(self):
return self.name
You see votes in Item model right. That's a problem. I use makemigrations migrate command. But I still get no such column error.
Edit:
This is makemigrations vs_chart output
Migrations for 'vs_chart':
vs_chart\migrations\0001_initial.py:
- Create model Item
- Create model Poll
- Add field poll to item
This is migrate command output.
Operations to perform:
Apply all migrations: vs_chart
Running migrations:
No migrations to apply.
Before you add field poll to item, you may try to provide default value for ForeignKey, absence of default value may cause this issue:
poll = models.ForeignKey('Poll',on_delete=models.CASCADE, default=0)

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.

ManyToManyField Serializer throws "This field must be unique" error

I am trying to create a Many-To-Many relationship between two models- Author and Book. My use-case is that I should be able to add a new book to the database with an author that already exists in the database.
models.py
class Author(models.Model):
author_id = models.CharField(max_length=20, primary_key=True)
name = models.CharField(blank=True, null=True)
def __unicode__(self):
return self.name
class Meta:
ordering = ('author_id',)
class Book(models.Model):
title = models.CharField(max_length=50, primary_key=True)
authors = models.ManyToManyField(Author)
def __unicode__(self):
return self.title
class Meta:
ordering = ('title',)
serializers.py
class AuthorSerializer(serializers.ModelSerializer):
class Meta:
model = Author
fields = ('author_id', 'name')
class BookSerializer(serializers.ModelSerializer):
authors = AuthorSerializer(many=True)
class Meta:
model = Book
fields = ('title', 'authors')
def create(self, validated_data):
book = Book.objects.create(name=validated_data['title'])
for item in validated_data['authors']:
author = Author.objects.get(author_id=item['author_id'])
book.authors.add(author)
return book
Let's say my Author table already has an Author:
1, George RR Martin
Now if I want to add a new book with an existing author, this is the request I send using httpie:
http -j POST http://localhost/books title="The Winds of Winter" authors:='[{"author_id":"1"}]'
and when I do, I get this error:
Output Error
{
"authors": [
{
"author_id": [
"This field must be unique."
]
}
]
}
It seems like the AuthorSerializer is being called which checks the provided author_id against the ones in the database already and throws this error.
Any help on this would be appreciated.
Is there a specific reason you have to use a custom PK field?
Django automatically creates primary key fields for you. If you simply delete that field from your model and your serializer (and create/run a migration on your database), you won't have to specify the pk in your POST call from your frontend, and Django will create an AutoField that auto-increments your model's id:
class Author(models.Model):
# Remove this line and run makemigrations.
# author_id = models.CharField(max_length=20, primary_key=True)
name = models.CharField(blank=True, null=True)
def __unicode__(self):
return self.name
class Meta:
ordering = ('author_id',)
If not, consider using an models.AutoField rather than models.CharField for your primary key field, and again, don't include this in your POST call.
Note, that if you already have a big database created, you might have to do some intricate work in your migration, a la this answer:

Django Migration Missing ManyToManyField

I've added a ManyToManyField to my app. Every restaurant can fall under many categories, and each category can be applied to many restaurants. The app has been working and running, and my models look like this:
class Category(models.Model):
class Meta:
verbose_name_plural = "categories"
title = models.CharField(max_length=100)
def __unicode__(self):
return self.title
class RestaurantInfo(models.Model):
name = models.CharField(max_length=100)
aboutUs = models.TextField(max_length=10000)
founded = models.DateField()
categories = models.ManyToManyField(Category)
def __unicode__(self):
return self.name
The ManyToManyFied is what is new. However, make migrations finds no changes to make.
Looks like you are not supplying app_name to makemigrations command.
python manage.py makemigrations app_name
If you won't supply app_name, Django won't detect changes made to your models.