I'm getting a 'circular import' error when trying to makemigrations in Django. The two models in question are these. The error is being flagged on Team.
from django.db import models
from django.contrib.auth.models import User
from footballapi.models.team import Team
from footballapi.models.bio import Bio
class Player(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.ForeignKey(Bio, on_delete=models.CASCADE)
teams = models.ManyToManyField(Team, on_delete=models.CASCADE, related_name="members")
from django.db import models
from footballapi.models.player import Player
class Team(models.Model):
name = models.CharField(max_length=50)
roster_spot = models.ForeignKey(Player, on_delete=models.CASCADE)
I think the issue is with the ManyToManyField, and I keep reading that I should use a string instead of the import. But I've tried every combination of words and can't find the right string. What should it be? By the way, these models are all from the same app.
Besides the classes you can also use a string "app_name.model_name" for a foreignkey relationship thus avoiding to import each other.
teams = models.ManyToManyField("app_name.Team", on_delete=models.CASCADE, related_name="members")
Alternatively, you could change your datamodel with a through table in your m2m relationship. Using this table you could set a boolean indicating if a player is playing roster_post. Check out the docs: https://docs.djangoproject.com/en/4.1/ref/models/fields/#django.db.models.ManyToManyField.through
Related
I have installed MongoDB in my Django project. Because is the first time I use Mongo, I decided to try how it works and I created a simple program to store data ( price and quantity in my case).
The project is called "exchange" and it has 2 folders: exchange and app.
This is the file models.py from 'app' folder:
from django.db import models
from djongo.models.fields import ObjectIdField, Field
from django.contrib.auth.models import User
class Profile(models.Model):
_id = ObjectIdField()
user = models.ForeignKey(User, on_delete=models.CASCADE)
class Order(models.Model):
_id = ObjectIdField()
profile = models.ForeignKey(Profile, on_delete=models.CASCADE)
datetime = models.DateTimeField(auto_now_add=True)
price = models.FloatField()
quantity = models.FloatField()
#ips = models.Field(default=[])
#subprofiles = models.Field(default={})
This is the file admin.py
from django.contrib import admin
from .models import *
admin.site.register(Profile)
admin.site.register(Order)
This is how I set the database in the file settings.py of the exchange folder
DATABASES = {
'default': {
'ENGINE': 'djongo',
'NAME': 'engine',
}
}
So after made the migrations and create the superuser, I run the server, I went into the section Admin than in Profile, and I created a profile choosing the only option available (my superuser).
At this point I created an order in the Orders section: so I chose in the "profile" field the only option available (the profile created before), then I filled the other 2 fields (price and quantity), but when I try to save it, appears above the field "profile" the following error:
"Select a valid choice. That choice is not one of the available choices."
I cannot understand where I am wrong.
Thanks in advance for your help!
The issue is that ForeignKey by default appends _id to the property name. In your above example, it is trying to use the property user_id on Profile and profile_id on Order.
The solution is to update the ForeignKey to:
profile = models.ForeignKey(Profile, db_column='profile', on_delete=models.CASCADE)
What you change db_column to may depend on how you have your schema set up inside mongodb, but I was receiving this same error and point the db_column to the correct property fixed it for me.
OMG #Adam Berg , I have been trying to resolve this issue for more than past 4 hours .Your answer resolved it within in mints .Thank you so much , your work is much appreciable.
import datetime,os
from djongo import models
class test1(models.Model):
name = models.CharField(max_length=100)
class Profile(models.Model):
user = models.ForeignKey(test1, db_column='user',on_delete=models.CASCADE)
This Will help you to perform all the foreign key related Query.
I have the following models in my models.py file in my django project
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.conf import settings
class CustomUser(AbstractUser):
pass
# add additional fields in here
class PDFForm(models.Model):
pdf_type=models.IntegerField(default=0)
pdf_name=models.CharField(max_length=100,default='')
file_path=models.FileField(default='')
class FormField(models.Model):
fk_pdf_id=models.ForeignKey('PDFForm', on_delete=models.CASCADE,default=0)
field_type=models.IntegerField(default=0)
field_page_number=models.IntegerField(default=0)
field_x=models.DecimalField(max_digits=6,decimal_places=2,default=0)
field_y=models.DecimalField(max_digits=6,decimal_places=2,default=0)
field_x_increment=models.DecimalField(max_digits=6,decimal_places=2,default=0)
class Meta:
ordering= ("field_page_number", "field_type")
class UserData(models.Model):
fk_user_id=models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE,default=0)
field_type=models.IntegerField(default=0)
field_text=models.CharField(max_length=200,default='')
field_date=models.DateField()
Here is how the models are related
1) a pdfform contains a pdf form and path for it on the file system
2) A pdfform has multiple FormFields in it. Each field has attributes, and the specific one under discussion is field_type
3)The UserData model has user's data, so one User can have multiple rows in this table. This model also has the field_type column.
What I am trying to query is to find out all rows present in the Userdata Model which are present in the FormField Model ( matched with field_type) and that are of a specific PDFForm.
Given that the Many to Many relationship in django models cannot happen between no unique fields, how would one go about making a query like below
select a.*, b.* from FormField a, UserData b where b.fk_user_id=1 and a.fk_pdf_id=3 and a.field_type=b.field_type
I have been going through the documentation with a fine toothed comb, but obviously have been missing how django creates joins. what is the way to make the above sql statement happen, so I get the required dataset?
I think UserData is missing a relation to FormField, but if you had this relation you could do:
UserData.objects.filter(
fk_user_id=1, # Rename this to user, Django wilt automicly create a user_id column
form_field__in=FormField.objects.filter(
fk_pdf_id=<your pdfid> # same as fk_user_id
)
)
Edit updated models
When you use a ForeignKey you don't have to specify the _id or default=0, if you don't always want to fill the field its better to set null=True and blank=True
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.conf import settings
class CustomUser(AbstractUser):
pass
# add additional fields in here
class FieldTypeMixin:
TYPE_TEXT = 10
TYPE_DATE = 20
TYPE_CHOISES = [
(TYPE_TEXT, 'Text'),
(TYPE_DATE, 'Date'),
]
field_type=models.IntegerField(default=TYPE_TEXT, choises=TYPE_CHOISES)
class PDFForm(models.Model):
pdf_type = models.IntegerField(default=0)
pdf_name = models.CharField(max_length=100,default='')
file_path = models.FileField(default='')
class FormField(models.Model, FieldTypeMixin):
pdf_form = models.ForeignKey('PDFForm', on_delete=models.CASCADE)
field_page_number = models.IntegerField(default=0)
field_x = models.DecimalField(max_digits=6,decimal_places=2,default=0)
field_y = models.DecimalField(max_digits=6,decimal_places=2,default=0)
field_x_increment = models.DecimalField(max_digits=6,decimal_places=2,default=0)
class Meta:
ordering = ("field_page_number", "field_type")
class SubmittedForm(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, models.CASCADE)
pdf_form = models.ForeignKey(PDFForm, models.CASCADE)
class SubmittedFormField(models.Model, FieldTypeMixin):
submitted_form = models.ForeignKey(SubmittedForm, models.CASCADE)
form_field = models.ForeignKey(FormField, models.CASCADE, related_name='fields')
field_text = models.CharField(max_length=200,default='')
field_date = models.DateField()
class Meta:
unique_together = [
['submitted_form', 'form_field']
]
I am very new to Django.
Can you please give a boilerplate of models how to relate two models between each other.
--Below is Section model
from articles.models import Article
# Create your models here.
class Section(models.Model):
#associations
user = models.ForeignKey(settings.AUTH_USER_MODEL)
article = models.ForeignKey(Article) #Article
--Below is Article model
from sections.models import Section
User = settings.AUTH_USER_MODEL
# Create your models here.
class Article(models.Model):
owner =models.ForeignKey(User, null=False)
sections = models.ManyToManyField( Section )
However. I got the below error:
ValueError: Cannot create form field for 'article' yet, because its related model 'articles.models' has not been loaded yet
Thanks All
B
Breaking cyclic imports
You defined a cyclic import: one module first has to import the other module, but the other module fist has to implement that module, so you defined a cycle.
In Django, one does not per se has to use a class reference to make ForeignKeys, one can use strings that refer to the correct model. In that case the Django framework, will later resolve these.
So we can break the cycle, for example with:
# sections/models.py
# no import from articles
# Create your models here.
class Section(models.Model):
#associations
user = models.ForeignKey(settings.AUTH_USER_MODEL)
# we use a string literal
article = models.ForeignKey('articles.Article', on_delete=models.CASCADE)
and then in the articles/models.py:
# articles/models.py
from sections.models import Section
User = settings.AUTH_USER_MODEL
# Create your models here.
class Article(models.Model):
owner = models.ForeignKey(User, null=False)
sections = models.ManyToManyField(Section)
So here we no longer import articles/models.py in the sections/models.py, and thus we break the cyclic import.
Note that you need to specify an on_delete for a ForeignKey, for example models.CASCADE.
Django's reverse relations
For this specific application however, it seems that you make a double relation between Section and Article, that basically is one relation, you should not do that, Django automatically writes the reverse relation, what you probably want to do, is give it a proper name, for example:
# sections/models.py
# no import from articles
# Create your models here.
class Section(models.Model):
#associations
user = models.ForeignKey(settings.AUTH_USER_MODEL)
# we use a string literal
article = models.ForeignKey(
'articles.Article',
on_delete=models.CASCADE,
related_name='sections'
)
and for articles/models.py:
# articles/models.py
User = settings.AUTH_USER_MODEL
# Create your models here.
class Article(models.Model):
owner = models.ForeignKey(User, null=False)
# no relation to section
Here we can obtain all Sections that relate to some_article with some_article.sections.all().
I'm using Django 1.8rc1. When I try to do a makemigrations with this models.py:
from django.db import models
from datetime import datetime
class TrackedModel(models.Model):
created_date = models.DateField()
modified_date = models.DateField()
class Meta:
abstract = True
class Project(models.Model):
name = models.CharField(max_length=12)
due_date = models.DateField()
complete_date = models.DateField(default=datetime.now)
I am getting:
TypeError: Cannot create a consistent method resolution
order (MRO) for bases Model, TrackedModel
I can't even see where it would be getting confused over methods with such a simple abstract model. In case you're wondering, the Project model is inheriting from models.Model in the example but that was just to troubleshoot -- ultimately I want Project to inherit from TrackedModel.
What am I missing?
Figured it out. The migration history got me again. I had to clear out the files in my app's migrations folder. Apparently it had stored a previous set of models that were not set up right, during a previous migration.
I have simplified my models down a to make it clearer what I am trying to do.
(models.py in app Teams)
from django.db import models
from django.contrib.auth.models import User
import datetime
class Team(models.Model):
users = models.ManyToManyField(User)
team_title = models.CharField(max_length=200)
team_description = models.CharField(max_length=200)
def __unicode__(self):
return self.team_title
(models.py in app Documents)
from django.db import models
import datetime
class Document(models.Model):
teams = models.ManyToManyField("Teams.Team", blank=True)
document_title = models.CharField(max_length=200)
document_description = models.TextField()
def __unicode__(self):
return self.document_title
What I want to achieve is getting a list of users who have are associated with a Document by first getting all the teams associated with the document and then from this getting all the users associated with those teams.
My attempts so far have gone something like this
(view.py in app Documents)
from django.contrib.auth.models import User
from Documents.models import *
from Teams.models import *
def docUsers(request, doc_id):
current_document = Documents.objects.get(pk = doc_id)
associated_users = current_document.teams.all().users
....
Error: 'QuerySet' object has no attribute 'users'
associated_users = current_document.items.all().users.all()
Error: 'QuerySet' object has no attribute 'users'
associated_users = current_document.items.users.all()
Error: 'ManyRelatedManager' object has no attribute 'users'
Am I going about this the wrong way?
Well, yes. current_document.teams.all() is a queryset - more or less, a list - of Teams. It doesn't make sense to ask for current_document.teams.all().users, as a queryset doesn't itself have a 'users' attribute, hence the error. users is an attribute of each Team element within that queryset. So, one way of doing it would be to iterate through the queryset and ask for the users associated with each team.
However, that would be hopelessly inefficient - one database call for each team. A much better way is to ask the database directly: give me all the users who are in teams associated with the current document. Like this:
User.objects.filter(team__documents=current_document)