Django signal receiving across apps - django

I have a main_app, and app2. main_app is essentially a list of items with data, and app2 has more information about said items.
main_app isn't supposed to know about app2, but app2 can import from main_app.
Within main_app/signals.py, I have
import django.dispatch
mysignal = django.dispatch.Signal(providing_args=['uid'])
In main_app/views.py, I have a view which renders various main_templates, containing the details of the item, a view for editing, and one for submitting said edited data. The idea is that a signal is sent when each of those is called and, app2 receives this. main_template uses the "with" call to get template2 and that app's information.
In app2/processes.py I have the following:
import django.dispatch
from django.dispatch import receiver
import my models
from main_app.signals import mysignal, (mysignal2, etc)
Then for each method, I have
#receiver(mysignal)
def foo(sender, **kwargs) etc
OK... So, in main_app/views.py, if I have the line:
from app2.processes import mysignal, mysignal2 etc
Everything works smoothly. But I want to remove any reliance on app2 in main_app. As far as I am concerned, app2 is just importing these signals from main_app/signals.py.
But if I try to get rid of the above line and put the following into main_app/views.py
from main_app.processes import mysignal, my...
It doesn't work...I don't get an error but the data from app2 doesn't render into the template, and I really don't see why....Any ideas?

Your signal receivers in app2 are probably not registered. Simple check: put raise Exception("I was imported!"); as the first line in app2/processes.py. You probably will never see that exception. You will have to make sure the signal receivers are being registered. You can do this by import app2.processes somewhere Django will look. For example in app2/models.py.

Related

Django migrating from scratch fails: 'no such table', after adding signal receivers

I added some signal receivers to my code and everything was working fine, until I pushed it to version control and the CI/CD pipeline failed. On trying to migrate, it would complain with:
django.db.utils.OperationalError: no such table: badges_badge
But the migrations were working on my machine!
The CI/CD starts from scratch though, so I tried deleting my db.sqlite3 locally, then tried to re-migrate with python manage.py migrate:
django.db.utils.OperationalError: no such table: badges_badge
So migrating from an existing db worked, but not from a new one.
My signals.py:
from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver
from badges.badge_stuff import badges
#receiver(post_save)
def update_badges(sender, **kwargs):
for badge in badges:
badge.update()
My apps.py:
from django.apps import AppConfig
class BadgesConfig(AppConfig):
name = 'badges'
def ready(self):
# Register signal listeners.
from . import signals
Why would it work with an existing db, but not when initialising it? How to fix this?
I had this issue and it was because of how I was registering my signals.
The problem is that the code in apps.ready() runs before any migrations, so if signals.py depends on models that don't exist in the db yet (e.g. when migrating from scratch), it'll fail. This might happen when your signals.py imports other modules which then depend on your models.
Here, badges.badge_stuff.badges imports the Badge model, which is created on first migration. So it cannot find it.
To fix this, we can use the post_migrate signal to register all of our signals after any migrations, so any necessary models will be created before any signal code runs.
Modify the above to:
from django.apps import AppConfig
from django.core.signals import pre_save, post_migrate
class BadgesConfig(AppConfig):
name = 'badges'
def register_signals(self, **kwargs):
# If your signals are decorated with #receiver, the line below is all you need
from . import signals
# Otherwise, explicitly connect the signal handler
pre_save.connect(signals.my_callback)
def ready(self):
post_migrate.connect(self.register_signals, sender=self)
And hopefully running your migrations should now work!
Remember to register your app in INSTALLED_APPS using this new AppConfig in settings.py:
INSTALLED_APPS = [
...
'badges.apps.BadgesConfig',
# Or just 'badges' for Django 4.0+
...
]

Debugging while developing Django apps

I'm aware of pdb built-in Python library for debugging Python programs and scripts. However, you can't really use it for debugging Django apps (I get errors when I try to use it in views.py). Are there any tools that I can use when Django's traceback isn't helpful ?
EDIT:
from .forms import TestCaseForm, TestCaseSuiteForm
from .models import TestCase, TestSuite
from django.contrib.auth.forms import UserCreationForm
from django.views.generic import FormView, ListView
from django.contrib.auth.models import User
from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required
from django.contrib.auth import logout
import pdb
class ListAllTestSuites(ListView):
template_name = 'list.html'
context_object_name = 'username'
def get_queryset(self):
pdb.set_trace() # <-- setting a trace here to diagnose the code below
queryset = {'test_suites': TestSuite.objects.filter(user=self.request.user),
'username': self.request.user}
return queryset
you forgot the exact error message and full traceback, and, more importantly, you forgot to explain how you executed this code to get this result...
But anyway: from the error message, you're obviously trying to execute your view file as a plain python script (cf the reference to __main__). This cannot work. A view is a module, not a script, and, moreover, any module dependending on Django needs some setup done to be imported (which is why we use the django shell - ./manage.py shell - instead of the regular Python one).
For most case, you can just launch the django shell, import your module and use pdb.runcall() to execute some function / method under the debugger (no need to put a breakpoint then, but that's still possible).
Now views require a HTTPRequest as first argument which make them a bit more cumbersome to debug that way (well, there is django.tests.RequestFactory but still...), so your best bet here is to set your breakpoint, launch your devserver (or restart it - if it didn't already did, as it should), point your browser to the view's url, and then you should see the debugger's prompt in your devserver's terminal.

Django unable to load model into views

I am trying to import my models into views.py but I am unable to do so. However I am able to register them on the admin site but when I use the same code I used in admin.py to import the models into views.py, I get an error. I am using djongo so I am not sure if that changes anything about how to import them and I cannot seem to find the documentation for it.
models.py
from djongo import models
class Round(models.Model):
round_num = models.IntegerField(default=0)
admin.py
from django.contrib import admin
from .models import Round
admin.site.register(Round)
views.py
from .models import Round
When I try and run my views.py file I get the following error: ModuleNotFoundError: No module named 'main.models'; 'main' is not a package
Also my views, admin, and models file are all in the same directory. I have made the migrations and I can see my Round model in MongoDB. The only thing I cannot do is import it to the view
You need to have an __init__.py file in your directory. It should be inside of your main folder and at the same level as your views.py and models.py
As a workaround, since the models properly migrate to MongoDB. Using pymongo I have just connected to Mongo and have rendered data into my views this way. It works fine so if anybody else has an issue loading in their models, you can always just connect directly to the DB.

Import a django app view in another app view

I have two django apps and I've called a view of app1 in app2, like this:
#app: app1
#someview.py
def a_view(request, someparam):
#some code here
#app: app2
#otherview.py
from app1.someview import a_view
def another_view(request):
param = 1
a_view(request, param)
def view2(request):
#some code
It works fine. My problem is that now I want to call a view from app2 in app1. So I add the import statement in someview.py like this:
#app: app1
#someview.py
from app2.otherview import view2
def a_view(request, someparam):
#some code here
The result is an ImportError "cannot import name view2".
Can anyone tell me why this happen?
The second import shadowing the first one ... Try like
import app2.otherview
or
from app2.views as app2_views
You can't do this because makes a loop.
You must add functions in another file and import in app1 and app2 separately.

Django path error - No module named models

I have an import error in a Django app, I guess it's pretty simple but I can't figure it out…
It's a simple notepad app, called «notes» with 2 models, «note» & «category». To clean things up, I wanted to seperate each models views & urls, so here is what I get:
/notes
admin.py
forms.py
models.py
/urls
category.py
note.py
/views
category.py
note.py
The problem is that my views don't find the models, here is the Traceback - http://dpaste.com/hold/539425/ and parts of the code: http://dpaste.com/hold/539416/
I didn't mention the _init_.py files in the above snippet, but I double-checked all of them…
Your code pastie says from notes.models import Category, Note but your traceback says from models import Category, Note. It's hard to tell if those are the same line because you're only pasting snippets. Still, it should be 'from notes.models import foo' always.
Are you sure you're always referencing the notes app in your models import?
UPDATE:
If you're using the correct from foo.models import bar syntax, then my next thoughts are that you've possibly got a circular dependency that's stopping Python importing things from the models file.
But the traceback implies the notes/models.py can't be found. So... when you say you double-checked the init.py files, that doesn't mean they're right. :p There should be one in notes/ and also in notes/urls/ -- they don't have to contain anything.
It should be
from notes.models import Category, Note