1

Having a Model in file MyApp/models/Artwork.py:

class Artwork(models.Model):
    class Meta:
        verbose_name = _('Artwork')
        verbose_name_plural = _('Artworks')

    def __init__(self, *args, **kwargs):
        super(Artwork, self).__init__(*args, **kwargs)

    objects = ArtworkManager()

And an action in file: MyApp/functions/actions.py

from MyApp.models import Artwork

import pprint;

def lock_artwork(request, id):
    pprint.pprint(Artwork)
    try:
        art = Artwork.objects.get(pk=id)
    except ObjectDoesNotExist:
        raise Http404()

In MyApp/models/__init__.py:

from .Artwork import Artwork

I get the curious error of not having the attribute objects in my model, which is there.

Stacktrace:

web_1  | <module 'MyApp.models.Artwork' from '/app/MyApp/models/Artwork.py'>
web_1  | Internal Server Error: /en/artwork/lock/2/
web_1  | Traceback (most recent call last):
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
web_1  |     response = get_response(request)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 115, in _get_response
web_1  |     response = self.process_exception_by_middleware(e, request)
web_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 113, in _get_response
web_1  |     response = wrapped_callback(request, *callback_args, **callback_kwargs)
web_1  |   File "/app/MyApp/functions/actions.py", line 72, in lock_artwork
web_1  |     art = Artwork.objects.get(pk=id)
web_1  | AttributeError: module 'MyApp.models.Artwork' has no attribute 'objects'

Something obvious I'm missing?

Daniel W.
  • 31,164
  • 13
  • 93
  • 151
  • 2
    Your model does not belong in `MyApp/models/Artwork.py`, but in `MyApp/models.py`. Then your import actually imports that model and not the spurious module containing it. – user2390182 May 14 '20 at 13:50
  • 1
    @schwobaseggl That's not a good idea, I have 10 models which would result in a very very big file. Everything is working but not this little thingy. According to other answers it's no problem to seperate models into their own files. – Daniel W. May 14 '20 at 13:53
  • @DanielW. Possible duplicate or answer here: https://stackoverflow.com/a/5534251/12581324, Remember to check the docs for newer version of that code, as the answer is 5 years old already. – Paaksing May 14 '20 at 13:55
  • I think you are importing a file in `actions.py` not the model itself so it does not have any objects – Hisham___Pak May 14 '20 at 13:55
  • @Paaksing that's actually what I'm using and what is working everywhere else. See the first line in the trace which is the output of `pprint(Artwork)` – Daniel W. May 14 '20 at 13:55
  • 1
    you should have this instead `from MyApp.models.Artwork import Artwork` – Hisham___Pak May 14 '20 at 13:57
  • @Hisham___Pak that actually did the trick! But EVERYWHERE else in my code I have it not like you suggesting but none of that generates errors. – Daniel W. May 14 '20 at 14:00
  • Something else must've been wrong. By the way should I post this as an answer? – Hisham___Pak May 14 '20 at 14:01
  • @DanielW. Reference to this answer https://stackoverflow.com/a/51384521/12581324 and add the object attr to your model, but remember, this is NOT the normal approach – Paaksing May 14 '20 at 14:03
  • 2
    What you really should do to keep your models separate and readable: import them from the submoules in yours `models/__init__.py`. And everywhere else, import them directly from `models`. But do **NOT** name the submodules the same as the models. That will result in conflicting names. – user2390182 May 14 '20 at 14:03

1 Answers1

1

For all of Django's automagic (migrations, model loading, ...) to work, models have to live in the namespace of their app's models! It does not matter whether that is a plain module or a package. What we often do to separate models in different modules within an app is the following:

MyApp
    models
        __init__.py
        artwork  # not the name of any model inside it!
        other

And inside the __init__.py, you import all the models from the submodules:

# __init__.py
from .artwork import Artwork
from .other import OtherModel, YetAnotherModel

That way, models.Artwork resolves to the actual model and is picked up by all of django's internal magic. You can now also import the Artwork model straight from MyApp.models anywhere in your code:

# e.g. some views.py
from MyApp.models import Artwork

On a side note: 10 models in a file is not that much. I would only split that if there are clear semantic separations and no circular references (in which case you could argue for separate apps to begin with). If dozens of models and hundreds of lines in a file should are an issue, you might want to look for a better IDE ;-)

user2390182
  • 72,016
  • 6
  • 67
  • 89
  • What is confusing me: There is one place my code above gives the error but in all the other spots there is no problem and the code is working inside Django. – Daniel W. May 15 '20 at 13:18
  • Example: This is working `latest_state = ArtworkState.objects.filter(artwork=obj).latest()` but this is not `art = Artwork.objects.get(pk=id)`; both models (Artwork and ArtworkState) are in the same folder the same way with identical naming pattern. – Daniel W. May 15 '20 at 13:20