Circular Import Nightmare How to resolve

Hello,

I am relatively new to Django–but seem to pick it up fairly quickly.
I only have this one problem however that I cant resolve and I feel like the solution is right before my eyes, and I can’t seem to spot it.

It may sound elementary to you but I can’t figure this out.

Say in my models.py I have a model–say Post, and a ReadingList model–so a person can create a Post reading list, if you will.

The Post model is written above the ReadingList model. I want the Post model to relate to the reading model but it does not relate it gives me a “Model not defined” error, you the one i’m talking about.

When I place the ReadingList model before the Post it works, but thats not what I need.

I need the Post model to relate to the ReadingList and the ReadingList to relate to Post at the same time so I can then display it in the users profile page.

This loop creates a circular import.

Now, is there another workaround to achieve this?

Or should I just give up Django all together?

I did read the docs about models, I understand how they work, but I can’t figure out how to properly relate all the models the way I want.

Are there other solution to achieve this?

Does this make sense at all? Do I confuse you?

Here is my models.py file


class Post(models.Model):
	title = models.CharField(max_length=300,blank=True)
	title_original = models.CharField(max_length=300,blank=True)

	slug = models.SlugField(max_length=300,blank=True)
	authors = models.ManyToManyField(User, null=True,blank=True)


	featured_image = models.ImageField(upload_to='media/FEATURED_IMAGES/',blank=True)

	gallery_image_01 = models.ImageField(upload_to='media/FEATURED_IMAGES/',blank=True)
	gallery_image_02 = models.ImageField(upload_to='media/FEATURED_IMAGES/',blank=True)
	gallery_image_03 = models.ImageField(upload_to='media/FEATURED_IMAGES/',blank=True)
	gallery_image_04 = models.ImageField(upload_to='media/FEATURED_IMAGES/',blank=True)
	gallery_image_05 = models.ImageField(upload_to='media/FEATURED_IMAGES/',blank=True)
	gallery_image_06 = models.ImageField(upload_to='media/FEATURED_IMAGES/',blank=True)

	description = RichTextField(max_length=30000,blank=True)

	published_date = models.DateTimeField(auto_now_add=False, blank=True)






	def get_absolute_url(self):
		return reverse(‘blog:Post, args=[self.slug])

	def __str__(self):
		return self.title



class ReadingList(models.Model):
	user = models.ForeignKey(User,on_delete=models.CASCADE, null=True, blank=True)
	title = models.CharField(max_length=300,blank=True)
	slug = models.SlugField(max_length=300,blank=True)



	def get_absolute_url(self):
		return reverse(‘blog:reading_list', args=[self.slug])

	def __str__(self):
		return self.title


Now when I try to access the posts via the Post model in my view, it gives me an error because the ReadingList is not related to the Post, there is not ReadingList field in the Post model to filter, does it make sense??

Here is my views.py file

You can see here how I try to access the reading list via the Post model in order to filter the posts, but cant, its not there, and I can’t relate it due to the error.

@login_required
def reading_list(request,reading_list):  


	rl = get_object_or_404(ReadingList, slug=reading_list)

	# whats going on


	posts = Post.objects.filter()

	return render(request, ‘blog/reading_list.html',{
				'rl':rl,
				'posts':posts
		})


You’re not showing either of the foreign key fields for your two models, so it’s really tough to answer you in specifics.

However, in general, start with reading the docs and examples at https://docs.djangoproject.com/en/4.1/ref/models/relations/#related-objects-reference

If the relationship is symmetrical, then you don’t need foreign keys in both models. What is the cardinality of the relationship between Post and ReadingList?

Hi,

I am also very new to Django myself but I think I was pulling my hair out about this for a few days. My solution was to put some quotations around the model name, e.g.
changing: authors = models.ManyToManyField(User, null=True,blank=True)
To: authors = models.ManyToManyField(‘User,’ null=True,blank=True)

I’m trying to clone Goodreads as a practice app–to hone my skills. I reached the part where users can create reading lists and add books to them.

Each user/profile should have the ability to create as many reading lists as he/she desires.

I designed the project with multiple apps.

1) for books | contains the books views
1) for members | contains the user profile and reading list views

Everything works until the ReadingList / Profile relationship starts. I’m having difficulties relating these two models properly. I tried every combination and none seem to work. Still can’t seem to make it right. Whenever I think that its working–some other issue arises.

Here as you can see–im importing the Book model from the books app so as to relate it to the reading list model.

The reading list model has books field with a ManyToManyField because a reading list can hold many books.

You can also see the profile model, with the reading list field with a ManyToManyField because a profile can have as many reading list as … need.

Everything works fine until the part where a user tries to access his/her profile and tries to access the reading lists / reading list pages.

My guess–the issue is in the filtering. When I filter the reading list for a certain instance of a user it gives me errors because there is no reading list to filter. See example below: Notice how I try to retrieve the reading lists?


def reading_lists(request):  

	reading_lists = ReadingList.objects.filter(user=request.user)

	return render(request, 'books/reading_lists.html',{
				'reading_lists':reading_lists
		})

Do I make sense??

Here is my (members) models.py:



from django.db import models
from django.urls import reverse
# Create your models here.

from django.contrib.auth.models import User

from ckeditor.fields import RichTextField
from books.models import Book 


class ReadingList(models.Model):
	#user = models.OneToOneField(User, on_delete=models.CASCADE, null=True)
	title = models.CharField(max_length=300,blank=True)
	slug = models.SlugField(max_length=300,blank=True)



	books = models.ManyToManyField(Book, null=True,blank=True)

	def get_absolute_url(self):
		return reverse('membership:reading_list', args=[self.slug])

	def __str__(self):
		return str(self.title)


class Profile(models.Model):
	user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, related_name='profile')
	biography_short = RichTextField(max_length=10000, null=True, blank=True)
	biography_full = RichTextField(max_length=10000, null=True, blank=True)

	profile_photo = models.ImageField(default='/MEMBERSHIP/PROFILE_PHOTOS/default_profile_photo.png', upload_to='PROFILE_PHOTOS')

	website_url = models.URLField(max_length=1000,null=True, blank=True)
	twitter = models.URLField(max_length=1000,null=True, blank=True)
	facebook = models.URLField(max_length=1000,null=True, blank=True)
	youtube = models.URLField(max_length=1000,null=True, blank=True)
	instagram = models.URLField(max_length=1000,null=True, blank=True)

	reading_list = models.ManyToManyField(ReadingList)

	def __str__(self):
		return str(self.user)





Here is my (members) views.py




from django.shortcuts import render,redirect,HttpResponseRedirect

# Create your views here.

from django.views import generic

from .models import Profile
from books.models import Book

from .models import ReadingList


from .forms import ProfilePhotoForm
from .forms import ProfileSettingsForm
from .forms import AccountSettingsForm

from django.contrib.auth.decorators import login_required

def front_page(request):  

	return render(request,'membership/front_page.html', {

		})

@login_required
def profile(request):  

	return render(request, 'membership/profile.html',{

		})

@login_required 
def profile_settings(request):

	if request.method == 'POST':
		photo_form = ProfilePhotoForm(request.POST, request.FILES)
		if photo_form.is_valid():
			photo_form.save()
			return redirect('membership:profile_settings')
	else:
		photo_form = ProfilePhotoForm()


	#profile_settings_form = ProfileSettingsForm()
	return render(request, 'profile_settings/profile_settings.html',{
			'photo_form':photo_form,
			#'profile_settings_form':profile_settings_form,
		})

@login_required 
def account_settings(request):  

	return render(request, 'profile_settings/account_settings.html',{
		
		})



class AuthorPublicProfile(generic.DetailView):
	model = Profile 
	template_name = 'membership/author_profile.html'
	object_context_name = 'profiles'

	def get_queryset(self):  
		return Profile.objects.all().exclude(user=self.request.user)

	def get_object(self, **kwargs):   
		pk = self.kwargs.get('pk') 
		author = Profile.objects.get(pk=pk) 
		books = Book.objects.filter(authors=pk)

		content = {
			'author':author,
			'books':books
		}

		return content

	def get_context_data(self, *args, **kwargs):
		context = super().get_context_data(**kwargs)

		return context 






def reading_lists(request):  

	reading_lists = ReadingList.objects.filter(user=request.user)

	return render(request, 'books/reading_lists.html',{
				'reading_lists':reading_lists
		})





def add_to_reading_list(request):
	pass








def reading_list(request,reading_list):  
	date_started_reading = DateStartedReading()
	date_finished_reading = DateFinishedReading()

	rl = get_object_or_404(ReadingList, slug=reading_list)



	books = Book.objects.filter(reading_list=rl)



	return render(request, 'books/reading_list.html',{

				'rl':rl,
				'books':books,
				'date_started_reading':date_started_reading,
				'date_finished_reading':date_finished_reading
			
		})






What are the actual errors that you are receiving here? Please post the complete tracebacks from the runserver console log for any errors that you’re looking for assistance with.

Here is the Traceback:


Environment:


Request Method: GET
Request URL: http://127.0.0.1:8005/membership/profile/reading_list/abc2/

Django Version: 4.1.2
Python Version: 3.9.10
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.sites',
 'django.contrib.sitemaps',
 'ihgr_app.apps.IhgrAppConfig',
 'accounts.apps.AccountsConfig',
 'membership.apps.MembershipConfig',
 'books.apps.BooksConfig',
 'mptt',
 'ckeditor',
 'import_export',
 'allauth',
 'allauth.account',
 'allauth.socialaccount',
 'django_comments_xtd',
 'django_comments',
 'rest_framework',
 'allauth.socialaccount.providers.google',
 'allauth.socialaccount.providers.facebook',
 'allauth.socialaccount.providers.twitter',
 'allauth.socialaccount.providers.github']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback (most recent call last):
  File "/Users/ariethan/Documents/django_apps/ihgr/virt/lib/python3.9/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
  File "/Users/ariethan/Documents/django_apps/ihgr/virt/lib/python3.9/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/ariethan/Documents/django_apps/ihgr/ihgr/membership/views.py", line 104, in reading_list
    books = Book.objects.filter(reading_list=rl)
  File "/Users/ariethan/Documents/django_apps/ihgr/virt/lib/python3.9/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/Users/ariethan/Documents/django_apps/ihgr/virt/lib/python3.9/site-packages/django/db/models/query.py", line 1420, in filter
    return self._filter_or_exclude(False, args, kwargs)
  File "/Users/ariethan/Documents/django_apps/ihgr/virt/lib/python3.9/site-packages/django/db/models/query.py", line 1438, in _filter_or_exclude
    clone._filter_or_exclude_inplace(negate, args, kwargs)
  File "/Users/ariethan/Documents/django_apps/ihgr/virt/lib/python3.9/site-packages/django/db/models/query.py", line 1445, in _filter_or_exclude_inplace
    self._query.add_q(Q(*args, **kwargs))
  File "/Users/ariethan/Documents/django_apps/ihgr/virt/lib/python3.9/site-packages/django/db/models/sql/query.py", line 1532, in add_q
    clause, _ = self._add_q(q_object, self.used_aliases)
  File "/Users/ariethan/Documents/django_apps/ihgr/virt/lib/python3.9/site-packages/django/db/models/sql/query.py", line 1562, in _add_q
    child_clause, needed_inner = self.build_filter(
  File "/Users/ariethan/Documents/django_apps/ihgr/virt/lib/python3.9/site-packages/django/db/models/sql/query.py", line 1407, in build_filter
    lookups, parts, reffed_expression = self.solve_lookup_type(arg)
  File "/Users/ariethan/Documents/django_apps/ihgr/virt/lib/python3.9/site-packages/django/db/models/sql/query.py", line 1217, in solve_lookup_type
    _, field, _, lookup_parts = self.names_to_path(lookup_splitted, self.get_meta())
  File "/Users/ariethan/Documents/django_apps/ihgr/virt/lib/python3.9/site-packages/django/db/models/sql/query.py", line 1709, in names_to_path
    raise FieldError(

Exception Type: FieldError at /membership/profile/reading_list/abc2/
Exception Value: Cannot resolve keyword 'reading_list' into field. Choices are: Alibris, Audible, abebooks, amazon_link, authors, awards_prizes, barnes_and_nobel, comments, date_added, date_finished, date_started, description, ebay, editions, favorites, featured_image, format_type, gallery_image_01, gallery_image_02, gallery_image_03, gallery_image_04, gallery_image_05, gallery_image_06, genres, id, isbn, isbn_10, isbn_13, language, pages, published_date_or, published_date_re, publisher, readinglist, slug, status, title, title_original, walmart_link



The relevent lines in the traceback are:

I don’t see where you’re showing the definition for Book in your post here, but you do show a many-to-many from ReadingList, which means the reverse reference would be readinglist, not reading_list, if that is the desired reference.