0

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()
  1. I don't understand what is apps? because it is not recognized by python
  2. I don't understand why i need schema_editor because it's not used
  3. 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

Mike
  • 3
  • 4

1 Answers1

0

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)
loxd
  • 1
  • 2
  • Hello thanks for your reply but maybe i didn't explain my issue well enough. I want to add a field to the manyTomany table that django I already created at the beginning. For that i have to add a new model that creates a new table and then copy what i have in my previous manyTomany table to the neew one with the new field. in your answer you don't talk about "through" attribute because you have not ManyToMany field. so that's not relevant for me because I can't change this model for now. What I want to do is to test the copy of the data in the old ManyToMany table to the new one – Mike Jul 24 '22 at 06:51