Why can you import UpdateView in "multiple ways" - django

Why do both of the following ways of importing UpdateView work?:
1. from django.views.generic import UpdateView
2. from django.views.generic.edit import UpdateView
I was assuming 2. was the correct way, and 1. would not work, but from testing both work.

What you see here is quite common (at least in some Python packages). If you define a .py file, that acts as a module. For example the django.views.generic.edit module maps on the django/views/generic/edit.py file [GitHub].
A directory is a Python module as well (due to the __init__.py file), but it does not contain any elements by default, hence that would mean that django.views.generic would be empty.
If we take a look at the django/views/generic/__init__.py file [GitHub], we see:
from django.views.generic.base import RedirectView, TemplateView, View
# ...
from django.views.generic.edit import (
CreateView, DeleteView, FormView, UpdateView,
)
# ...
__all__ = [
'View', 'TemplateView', 'RedirectView', 'ArchiveIndexView',
'YearArchiveView', 'MonthArchiveView', 'WeekArchiveView', 'DayArchiveView',
'TodayArchiveView', 'DateDetailView', 'DetailView', 'FormView',
'CreateView', 'UpdateView', 'DeleteView', 'ListView', 'GenericViewError',
]
# ...
This thus imports the UpdateView from the generic.py file, and re-exports the class.
You thus can reference to the class in two ways: through the module defined by the generic.py file, or through the re-export of the module of the directory, specified through the __init__.py file.
This is typically done to export a portion of the items that are defined in the files, export these under a more convenient name, or provide some extra classes at the module level (for example the __init__.py file defines the GenericViewError error).
This directory-level module thus "groups" interesting views together. For example the FormMixin is not exported at this level. The __init__.py here groups (popular) class-based views together, whereas the mixins, that are typically used to define such generic views, are still specific to a file.

Related

Django: cannot import name 'url_patterns'

I have a weird edge-case where I need to use the data stored in urls.py within a view, but since the urls.py file imports the view, I am getting a circular import error when I try to import the url data into the view.
cannot import name 'url_patterns'
Does Django have any way of grabbing all the url patterns within a view that could circumvent this error? The fact that the reverse() function exists indicates that it might.
You can solve this typically (well it depends a bit), by importing the urls in your view(s) locally. Like:
# urls.py
import someapp.views
url_patterns = [
url('some_url/', someapp.views.some_view),
]
and then import the urls in the views like:
# views.py
def some_view(request):
from someapp.urls import url_patterns
# ...
# do something with urlpatterns
# return response
pass
We here thus postpone the importing of the urls.py in the views, until the view function is actually called. By that time both the views.py and urls.py are (usually) already loaded. You can however not call the view in the views.py directly, since then the import is done before the urls.py is loaded.
Note that usually you do not have to import url_patterns, and you can use reverse(..) etc. to obtain a URL that corresponds to a view function (even passing parameters into a dictionary, etc.). So I really advice to look for Django tooling to handle URLs.
Found an answer:
from django.urls import get_resolver
url_patterns = set(v[1] for k,v in get_resolver(None).reverse_dict.items())

The `__init__.py` import multiple modules while they are not utilized within the file

I am reading /django/forms/__init__.py
"""
Django validation and HTML form handling.
"""
from django.core.exceptions import ValidationError # NOQA
from django.forms.boundfield import * # NOQA
from django.forms.fields import * # NOQA
from django.forms.forms import * # NOQA
from django.forms.formsets import * # NOQA
from django.forms.models import * # NOQA
from django.forms.widgets import * # NOQA
The __init__.py import multiple modules while they are not utilized within the files.
I assume they might be employed by others lived in the same dir, How Django achieve this?
The __init__.py import multiple modules
s/modules/names/ - the from somemodule import somename syntax exposes the somename name, not somemodule.
while they are not utilized within the files.
I assume they might be employed by others lived in the same dir
Actually this is a design pattern known as "facade" - the forms package hides it's inner implementation (in which submodule / subpackage is something defined) so
1/ the users can just import what they need from django.forms without having to care about the underlying modules / subpackages hierarchy,
and
2/ the mainainers can reorganize the underlying modules / subpackages hierarchy without breaking client code.
How Django achieve this?
This is nothing Django specific, it's just plain ordinary Python. Read Python's doc about modules and packages.

Flask Blueprints sharing

I want to make an API with Flask and it also needs to have an admin panel.
I guess that Blueprints are the way to go, but I don't want to make models twice.
My structure is going to be this:
- app
- api
- admin
- models
So my question is: How can I access the models in the models folder in my api blueprint and my admin blueprint?
Thanks in advance.
if you'd in a module within the api or admin folders you can import anything from a module in the models folder using this notation
from ..models.module_name import model1, model2, etc
for small projects i usually keep all the models in a single models.py file like:
[app]
[blueprint_1]
__init__.py
views.py
[blueprint_2]
[static]
[templates]
__init__.py
models.py
then from within any of your blueprint files just:
from ..models import model1, model2, etc
About the import, If your directory include __init__.py then it is a python package so . use for current dir. For example:
auth/
__init__.py
forms.py
views.py
#views.py
from forms import Form name
from . import auth_blueprint # imports from __init__.py
So if you wants to import from another directory you have to use .. to imports from __init__.py file let's say your models directory include those files :
models/
__init__.py
UserModel.py
Now let's import models for auth module :
#auth/views.py
from .. import models # import froms models/__init__.py
from ..models import UserModel

Why is __init.py__ not importing my views?

My views.py got bloated, and I decided to cut it up into smaller modules by creating a ./views directory with all the little .py files. Here's what I get when I start the test webserver:
File "/path/to/the/app/views/__init__.py", line 1, in <module>
from my_view import my_view
ImportError: No module named 'my_view'
My ./views directory contains __init__.py, which is several lines of:
from my_view import my_view
from my_other_view import my_other_view
#etc...
./views/my_view.py of course looks like:
def my_view(request):
#etc...
I've obviously overlooked something, but I can't think what. Can you see the error I have made?
I guess views is not in your PYTHON_PATH. Which is right. However this means you should use relative python imports:
from .my_view import my_view # note the leading dot
Or absolute import from your project root (which should be in your PYTHON_PATH):
from myapp.views.my_view import my_view

Django - split views into separate files while maintaining views.py

Hopefully this is a simple noob question. I'm working on my first large(ish) Django project. The first engineer on the project was following the default Django code layout. As things have grown we've recently split out models into their own directory with one file per model.
It's time to start doing the same for views. However, I don't want/need to do it all in one go. I'd like to just start moving things out of the default views.py one by one as I work on them. However, I'm having difficulty getting urls.py to work with both a views directory and views.py
Is this just going to cause a naming collision when I try to import 'views' in my urls.py file? Is the simple answer just to call "views" something else while I make the transition? Or just bite the bullet and do it all at once?
The direct answer is yes, you have a python naming collision. See for example Python Import Class With Same Name as Directory
You don't need to do it all as once though -- you can simply rename / move your views.py file or your new views directory. Moving the new directory would likely be easiest, then you won't have change your existing url routes.
There's nothing special about views.py files, as long as your urls.py points to the appropriate function, you can place them anywhere, and call them anything.
I recommend creating feature sub-directories within your app folder on your Django project. Then, simply import them from the new directory using the app.views namespace by using the from ... import * incantation. This will import any views without the module name prepended (e.g. what would normally be referenced by app_name.views.feature_one.view_class becomes app_name.views.view_class like you want). See below:
# app_name/views.py
from feature_one.views import *
from feature_two.views import *
# ... copy views from here
# new file: app_name/feature_one/views.py
# ... paste some views here
# new file: app_name/feature_two/views.py
# ... paste some other views here
# new file: app_name/feature_one/__init__.py
# ... this file can be blank. required for importing "feature_one" like a module
# new file: app_name/feature_two/__init__.py
# ... this file can be blank. required for importing "feature_two" like a module
Now, while your views will be spread across sub-directories, they are all imported with the same names into app_name.views so you can still reference the same names in urls.py despite having moved some views to other files.
Since you have divided models into their sub-apps, you can define urls specific to these sub-apps in the created sub directories and set up a url hierarchy. This is how your default urls.py will look like:
from django.conf.urls import include, patterns, url
urlpatterns = patterns('',
# ... snip ...
url(r'^comments/', include('your_website.comments.urls')),
url(r'^community/', include('your_website.community.urls')),
url(r'^contact/', include('your_website.contact.urls')),
# ... snip ...
)
where comments, community and contact are your newly created sub-apps/sub-directories. More info on how the url dispatcher works, here