Help with Admin forms validation error - python

I am quite new to Django, I'm having few problems with validation
forms in Admin module, more specifically with raising exceptions in the
ModelForm. I can validate and manipulate data in clean methods but
cannot seem to raise any errors. Whenever I include any raise
statement I get this error "'NoneType' object has no attribute
'ValidationError'". When I remove the raise part everything works
fine.
Then if I reimport django.forms (inside clean method) with a different alias (e.g. from django import forms as blahbalh) then I'm able to raise messages using blahblah.ValidateException.
Any tips or suggestions on doing such a thing properly ?
Here's an example of what I'm doing in Admin.py:
admin.py
from django import forms
from proj.models import *
from django.contrib import admin
class FontAdminForm(forms.ModelForm):
class Meta:
model = Font
def clean_name(self):
return self.cleaned_data["name"].upper()
def clean_description(self):
desc = self.cleaned_data['description']
if desc and if len(desc) < 10:
raise forms.ValidationError('Description is too short.')
return desc
class FontAdmin(admin.ModelAdmin):
form = FontAdminForm
list_display = ['name', 'description']
admin.site.register(Font, FontAdmin)
--
Thanks,
A

You problem might be in the * import.
from proj.models import *
if proj.models contains any variable named forms (including some module import like "from django import forms), it could trounce your initial import of:
from django import forms
I would explicitly import from proj.models, e.g.
from proj.models import Font
If that doesn't work, see if there are any other variables name "forms" that could be messing with your scope.
You can use introspection to see what "forms" is. Inside your clean_description method:
print forms.__package__
My guess is it is not going to be "django" (or will return an error, indicating that it is definitely not django.forms).

Related

Why isn't django.contrib.auth.authenticate() working here?

I'm writing a simple (for now) Django app. I'm having trouble with authentication: I'm trying to use all of the out-of-the-box components, and both in the app itself and in tests, I can't authenticate users. So, for example, here's a test that fails:
from django.conf import settings
from django.contrib.auth import authenticate
from django.contrib.auth.models import User
from django.test import TestCase
[...]
class UserTestCase(TestCase):
def setUp(self):
self.testu = User(username="thename", password="thepassword", first_name="thefirstname")
self.testu.save()
def testAuthenticate(self):
u = authenticate(username="thename", password="thepassword")
self.assertEqual(u.first_name, "thefirstname")
I get an AttributeError:
'NoneType' object has no attribute "first_name".
I think this is because authenticate() is returning None (representing that there is no such user).
This fails whether or not I include the line "self.testu.save()".
I have other tests that pass, so I don't think the problem is with the test infrastructure. I can successfully create users and retrieve their information from the database.
The only mention of User in models.py is:
from django.contrib.auth.models import User
I've read through a lot of documentation but can't figure out what's going on. Can anyone help? Thanks in advance.
You can not create a User object with a password like that. The password needs to be hashed. Therefore, you should use the .set_password(..) method [Django-doc]:
class UserTestCase(TestCase):
def setUp(self):
self.testu = User(username="thename", first_name="thefirstname")
self.testu.set_password("thepassword")
self.testu.save()
# …

Django: Global modification of readonly field appearance

I want to customize the field texture in django’s new “readonly mode”: E.g. foreign keys shall be displayed as links.
In general I identified the following options:
Implement custom fields for every model – results in code duplication
Reimplement django’s display_for_field method
Basically I could copy & paste the django.contrib.admin.utils module, insert my changes, override sys.modules['django.contrib.admin.utils'] = myutils but that's ugly because of maintainability in case of Django updates in the future.
So I decided to override only the display_for_fields method of django.contrib.admin.utils using the following approach to avoid duplication of Django code:
Override display_for_field function in django.contrib.admin.utils in settings.py:
from myapp.contrib.admin import utils
utils.override_method()
In myapp.utils.py:
from django.contrib.admin import utils
from django.contrib.admin.utils import *
def display_for_field_mod(value, field, empty_value_display):
if isinstance(field, models.ForeignKey) and value:
if field.related_model.__name__.lower() != 'user':
link_string = 'admin:myapp_' + field.related_model.__name__.lower() + '_change'
link = reverse(link_string, args=(value.id,))
return format_html('{}', link, value)
else:
return formats.localize(value)
else:
return display_for_field(value, field, empty_value_display)
def override_method():
utils.display_for_field = display_for_field_mod
But the problem is: display_for_field gets imported in django.contrib.admin.helpers using:
from django.contrib.admin.utils import (
display_for_field, [...]
)
So due to the scope of the imported funtion I cannot override this function from outside.
Do I miss some other obvious possibility? Is there a clean method to achieve this or is the only option to duplicate/modify django’s original code?
I came across a similar issue. If anyone's still looking for a solution, you just need to override the display_for_field in helpers, e.g.:
from django.contrib.admin import helpers, utils
def override_method():
helpers.display_for_field = display_for_field_mod
utils.display_for_field = display_for_field_mod
Only overriding helpers is sufficient, but it's a good idea to override utils as well, just in case.

Cannot import models from another app in Django

so I have 2 apps running in the same project.
My files are structured as follows:
/project_codebase
/project
__init.py
settings.py
urls.py
wsgi.py
...
/app1
...
/app2
...
manage.py
So, I for some weird reason have a different name for my base directory (that is, it ends with codebase). Hopefully, that is not an issue.
In my settings.py, I have this:
INSTALLED_APPS = [
...
'app1',
'app2',
]
Ok, so in my models.py (from app2), I can easily import models from app1 with from app1.models import *, however, when I use from app2.models import * in my models.py (from app1), I get an ImportError.
Any solutions to this?
This might be due to circular import issues. To avoid this you should load the model dynamically:
For recent versions of django (1.7+) use the application registry:
from django.apps import apps
MyModel1 = apps.get_model('app1', 'MyModel1')
For earlier django versions (<1.7):
from django.db.models.loading import get_model
MyModel1 = get_model('app1', 'MyModel1')
Note 1: If you want to define a ForeignKey relationship, there is no need for a separate import statement. Django has you covered on this:
If app1 is an installed app, you should define the ForeignKey relationship as follows:
# in app2.py
class MyModel2(models.Model):
mymodel1 = models.ForeignKey('app1.MyModel1')
Note 2: The get_model only works if app1 is an installed app and MyModel1 is the model you want to import from app1.
Note 3: Try to avoid wildcard import (from ... import *), as this is bad practice.
It's definitely a circular import.
But i think is what you need is to use models as some sort of RetationFields(ForeignKey, ManyToManyField or OneToOneField) arguments. So you need to skip import and use as so:
# app1/models.py
class Model1(models.Model):
relation_field = models.ForeignKey('app2.Model2')
From docs:
If you need to create a relationship on a model that has not yet been defined, you can use the name of the model, rather than the model object itself
To refer to models defined in another application, you can explicitly specify a model with the full application label
Just put str object as first argument to relation fields that leeds to <app_name>.<Model_name>.
Note: it's better to avoid importing everything from module(from <module_name> import *)
If you want to import only some specific module then do not use import *.
It will take more time load your all library and so can affect the speed of your app also.
If you want to use few modules from your second app then just add module name instead of whole libraries something like this:
from app2.models import Module1, Module2
or it may be circular import issue as other clarify.
Thanks.
i use this code always and it's work :)
from position_app.models import Member
You need to specify the model names you want to import, for ex from app1.models import ModelName1, ModelName2.
Make sure there is no name clash between one of your apps and one of the modules installed in your Python environment. If you use pip, you can run pip freezeto see a list of installed modules.
I had the same error when one of my apps was named 'packaging', and the packaging python module was installed.
I also face this problem when I try to import my model from another app in (django2.2)
But at last I Imported It and Its successfully working.
here is my two app:
INSTALLED_APPS = [
...
'categories',
'videos',
]
and this is the code for how I Imported it into videos/models.py file as a ForeignKey Connectivity
from django.db import models
class Videos(models.Model):
categories = models.ForeignKey('categories.Categories', related_name='categories', on_delete=models.CASCADE)
If want to see my Categories Model from categories/models.py file, you can check this code otherwise neglect it
from django.db import models
class Categories(models.Model):
category_name = models.CharField(max_length=50)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
It is a circular import
In my case I needed the imported class not for a relation field, but for use it inside a method instead.
If that's the case, I suggest to import inside the method, otherwise an AppRegistryNotReady("Models aren't loaded yet.") is raised.
class Student(CustomUser):
""" Usuario alumno """
class Meta:
verbose_name = "Alumno"
verbose_name_plural = "Alumnos"
def get_current_school_class(self):
""" Obtiene el curso actual de un alumno """
from school.models import SchoolClass, StudentClass
# proceed with the method...
it's not necessary to import models from others apps
just put the app.models in the foreignkey field and that's work ;)
app 1:
class model1(models.Model):
field=models.field type ...
app 2:
class model2(models.Model):
field=models.ForeignKey('app1.model1', on_delete. ...)
to avoid code correction :D

Import model in Django's settings.py

I'm trying to define a constant with the value of model's class in the settings.py to provide a dynamically-defined FK for one of my models:
from catalog.models import Product
PRODUCT_MODEL = Product
No surprise it's leading to an AppRegistryNotReady exception:
django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
since there was no call to django.setup() method.
If I add
import django
django.setup()
in front of the model's import, instead of AppRegistryNotReady exception, I'm getting
AttributeError: 'Settings' object has no attribute 'PRODUCT_MODEL'
when I'm using
from django.conf import settings
...
product = models.ForeignKey(
settings.PRODUCT_MODEL,
related_name='order_items')
Is there any way to implement this without errors?
I'm using Python 3.5 and Django 1.9.5.
You shouldn't import models or call django.setup() in your settings file.
Instead, use a string to refer to your model.
PRODUCT_MODEL = 'catalog.Product'
Then, in your models, you can use the setting.
product = models.ForeignKey(
settings.PRODUCT_MODEL,
related_name='order_items',
)
Note that the AUTH_USER_MODEL setting uses a string like this, you do not import the user model in the settings file.
Store the model name as a string.
In settings.py:
PRODUCT_MODEL = 'YourModel'
In your models.py:
from django.apps import AppConfig
....
field = models.ForeignKey(AppConfig.get_model(PRODUCT_MODEL))
(This works from Django 1.9.)
Use catalog.Product in settings and lazy import

beginner: python namespace collision?

Disclaimer: i am new to python but have drupal programming experience
I am reading the Definitive Guide to Django (http://www.djangobook.com/en/1.0/chapter07/). After issuing
python manage.py startapp books
python creates the books package with views.py inside. Later in the tutorial, we enter the following into that views.py file:
# Create your forms here.
from django import forms
from django.forms import form_for_model
from models import Publisher
PublisherForm = forms.form_for_model(Publisher)
TOPIC_CHOICES = (
('general', 'General enquiry'),
('bug', 'Bug report'),
('suggestion', 'Suggestion'),
)
class ContactForm(forms.Form):
topic = forms.ChoiceField(choices=TOPIC_CHOICES)
message = forms.CharField(widget=forms.Textarea())
sender = forms.EmailField(required=False)
def clean_message(self):
message = self.cleaned_data.get('message', '')
num_words = len(message.split())
if num_words < 4:
raise forms.ValidationError("Not enough words!")
return
Unless I typed something wrong or misunderstood something (either is likely), we now (seemingly) have a collision between forms (books/forms.py) and django forms. So, which does Python refer to above in
message = forms.CharField(widget=forms.Textarea())
This statement:
from django.forms import form_for_model
Really only pulls the name form_for_model into the module-global namespace, the already existing name forms is not affected. Even this:
import django.forms
would not be a problem, because it only makes the name available in its fully-qualified form, django.forms (which is unambigios and does not collide with forms).
Unlike PHP, Python only imports into the current namespace, and each module is its own namespace; imports in other modules do not affect the current namespace, and vice versa.
Although this example does not cause a conflict as pointed out if there is a conflict you can use from ____ import ___ as ___ to specify your own import name
http://docs.python.org/reference/simple_stmts.html#import

Categories

Resources