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)
Что я уже пробовал:
- Удаление базы данных и файлов миграций
- замена на through=main.SubstituableIngredient, как предложено в Django many-to-many 'str' object has no attribute '_meta' не помогает