AttributeError: объект 'str' не имеет атрибута '_meta' при попытке использовать поле Many to Many на self со сквозной моделью - Django

Версия Django - 4.0.4

Я создаю сайт-конструктор рецептов и пытаюсь создать таблицу Ingredient, в которой каждый ингредиент может иметь заменяемые ингредиенты. Например, ингредиент "желудевый сквош" имеет следующие заменяемые ингредиенты:

  • Название ингредиента: Butternut Squash. Пересчет: 1 чашка желудевого сквоша = 1 чашка баттернат сквоша
  • .
  • название ингредиента: тыква. Преобразование: 1 чашка желудевого сквоша = 1 чашка тыквы

Для достижения этой цели у меня есть класс Ingredient и класс SubstitutableIngredient в models.py. Я использую поле "многие ко многим" в Ingredient, которое использует "through" для связи с таблицей SubstitutableIngredient, поскольку у меня есть дополнительные поля, такие как "conversion". Я использую 'self', так как заменяемый ингредиент все равно является ингредиентом. При попытке makemigrations или migrate я получаю следующую ошибку: AttributeError: 'str' object has no attribute '_meta' when attempting to makemigrations or migrate. Трассировка стека показана ниже.

Мой код в Models.py следующий:

from django.db import models


# Create your models here.

class Ingredient(models.Model):
    title = models.CharField(max_length=200,
                             unique=True)  # unique field. There may only be one ingredient in the database with the same title.

    # many to many field
    substitutableIngredients = models.ManyToManyField(
        'self',
        through='SubstitutableIngredient',
        through_fields=('originalIngredient', 'newIngredient'),
    )

    def __str__(self):
        return self.title


class SubstitutableIngredient:
    originalIngredient = models.ForeignKey(Ingredient, on_delete=models.CASCADE, related_name="originalIngredient")
    newIngredient = models.ForeignKey(Ingredient, on_delete=models.CASCADE, related_name="newIngredient")

    # the conversion rules between the ingredients (e.g. 1 cup = 2 cups)
    conversion = models.CharField(max_length=200)

# A Cuisine has a title which is unique.
class Cuisine(models.Model):
    title = models.CharField(max_length=200, unique=True)

    def __str__(self):
        return self.title


# recipe class inherits from Model
class Recipe(models.Model):
    # attributes
    title = models.CharField(max_length=200)
    # every Recipe can have many ingredients and each ingredient can have many recipes.
    # relationship is modelled by the IngredientInRecipe model.
    ingredients = models.ManyToManyField(
        Ingredient,
        through='IngredientInRecipe',
        through_fields=('recipe', 'ingredient')
    )
    instructions = models.TextField(blank=True, null=True)
    vegetarian = models.BooleanField(blank=True, null=True)
    vegan = models.BooleanField(blank=True, null=True)
    glutenFree = models.BooleanField(blank=True, null=True)
    dairyFree = models.BooleanField(blank=True, null=True)
    sourceUrl = models.CharField(max_length=200, blank=True, null=True)
    image = models.CharField(max_length=200, blank=True, null=True)
    cuisines = models.ManyToManyField(Cuisine, blank=True, null=True)

    def __str__(self):
        return self.title


# Intermediary class working between Recipe and Ingredient.
class IngredientInRecipe(models.Model):
    recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)
    ingredient = models.ForeignKey(Ingredient, on_delete=models.CASCADE)
    unit = models.CharField(max_length=200)
    quantity = models.FloatField()

    def __str__(self):
        return self.recipe.title + "," + self.ingredient.title

Трассировка:

C:\[pathname]>python manage.py makemigrations
Traceback (most recent call last):
  File "C:[pathname]\manage.py", line 22, in <module>
    main()
  File "C:[pathname]\manage.py", line 18, in main
    execute_from_command_line(sys.argv)
  File "C:\Users\[pathname]\AppData\Local\Programs\Python\Python39\lib\site-packages\django\core\management\__init__.py", line 446, in execute_from_command_line
    utility.execute()
  File "C:\Users\[pathname]\AppData\Local\Programs\Python\Python39\lib\site-packages\django\core\management\__init__.py", line 440, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "C:\Users\[pathname]\AppData\Local\Programs\Python\Python39\lib\site-packages\django\core\management\base.py", line 414, in run_from_argv
    self.execute(*args, **cmd_options)
  File "C:\Users\[pathname]\AppData\Local\Programs\Python\Python39\lib\site-packages\django\core\management\base.py", line 455, in execute
    self.check()
  File "C:\Users\[pathname]\AppData\Local\Programs\Python\Python39\lib\site-packages\django\core\management\base.py", line 487, in check
    all_issues = checks.run_checks(
  File "C:\Users\[pathname]\AppData\Local\Programs\Python\Python39\lib\site-packages\django\core\checks\registry.py", line 88, in run_checks
    new_errors = check(app_configs=app_configs, databases=databases)
  File "C:\Users\[pathname]\AppData\Local\Programs\Python\Python39\lib\site-packages\django\core\checks\model_checks.py", line 36, in check_all_models
    errors.extend(model.check(**kwargs))
  File "C:\Users\[pathname]\AppData\Local\Programs\Python\Python39\lib\site-packages\django\db\models\base.py", line 1442, in check
    *cls._check_fields(**kwargs),
  File "C:\Users\[pathname]\AppData\Local\Programs\Python\Python39\lib\site-packages\django\db\models\base.py", line 1556, in _check_fields
    errors.extend(field.check(from_model=cls, **kwargs))
  File "C:\[pathname]\lesle\AppData\Local\Programs\Python\Python39\lib\site-packages\django\db\models\fields\related.py", line 1376, in check
    *self._check_relationship_model(**kwargs),
  File "C:\Users\[pathname]\AppData\Local\Programs\Python\Python39\lib\site-packages\django\db\models\fields\related.py", line 1603, in _check_relationship_model
    for f in through._meta.fields:
AttributeError: 'str' object has no attribute '_meta'

Я очень запутался, потому что следующий код, который почти идентичен моему, работает совершенно нормально. Код примера:

# Create your models here.

class Person(models.Model):
    name = models.CharField(max_length=50)

    # note the additional arguments here
    friends = models.ManyToManyField(
        'self',

        # recursive relationships to self with intermediary
        # through model are always defined as non-symmetrical
        # symmetrical=False,

        through='PersonFriend',

        # this argument is required to define a custom
        # through model for many to many relationship to self
        # position matters: 1 - source (from), 2 - target (to)
        through_fields=('person', 'friend'),
    )


class PersonFriend(models.Model):
    # required relationship-defining foreign keys
    # (note that the order does not matter, it matters
    # in 'through_fields' argument in 'friends' field of the 'Person' model)
    person = models.ForeignKey(Person, on_delete=models.CASCADE, related_name="person")
    friend = models.ForeignKey(Person, on_delete=models.CASCADE, related_name="friend")

    # additional fields
    comment = models.CharField(max_length=50)

Что я уже пробовал:

Вернуться на верх