How are clean_<fieldname>() methods defined/generated in django Forms? - django

I'm currently trying to understand how forms validation works in Django (version 3.2.4). In order to achieve that I'm reading the framework's source code.
But despite searching for it I didn't find where (nor how) are the clean_<fieldname>() methods generated/defined.
The only thing I found is where it's used (django/forms/forms.py::BaseFormL392).
Where are these methods defined?

Related

Can JS-DOM test code that uses Tailwind's peer / peer-invalid mechanism?

Tailwind offers a feature where you can give an input element the peer class and then, in a sibling element use the peer-invalid: pseudoclass to apply conditional stylings. This is commonly used to provide helper text when a form field is not valid.
I don't see how this can be tested in JS-DOM though, as JS-DOM doesn't have access to the actual CSS when it is just rendering components in unit tests.
The information I have seen about getting JS-DOM to use CSS at all is kinda sketchy, so I was wondering if it's even worth trying to get it to evaluate a bunch of tailwind classes in a NextJS/Jest/RTL project. I'm using Tailwind 3 so it's not even like I have a big file full of generated classes I could try and pass to JS-DOM :/
So can it be done? (Note the hard fact please mods!!!)
(And, somewhat more subjectively, should it be done? Or is there a better way to approach this?)

Specify typing for Django field in model (for Pylint)

I have created custom Django model-field subclasses based on CharField but which use to_python() to ensure that the model objects returned have more complex objects (some are lists, some are dicts with a specific format, etc.) -- I'm using MySQL so some of the PostGreSql field types are not available.
All is working great, but Pylint believes that all values in these fields will be strings and thus I get a lot of "unsupported-membership-test" and "unsubscriptable-object" warnings on code that uses these models. I can disable these individually, but I would prefer to let Pylint know that these models return certain object types. Type hints are not helping, e.g.:
class MealPrefs(models.Model):
user = ...foreign key...
prefs: dict[str, list[str]] = \
custom_fields.DictOfListsExtendsCharField(
default={'breakfast': ['cereal', 'toast'],
'lunch': ['sandwich']},
)
I know that certain built-in Django fields return correct types for Pylint (CharField, IntegerField) and certain other extensions have figured out ways of specifying their type so Pylint is happy (MultiSelectField) but digging into their code, I can't figure out where the "magic" specifying the type returned would be.
(note: this question is not related to the INPUT:type of Django form fields)
Thanks!
I had a look at this out of curiosity, and I think most of the "magic" actually comes for pytest-django.
In the Django source code, e.g. for CharField, there is nothing that could really give a type hinter the notion that this is a string. And since the class inherits only from Field, which is also the parent of other non-string fields, the knowledge needs to be encoded elsewhere.
On the other hand, digging through the source code for pylint-django, though, I found where this most likely happens:
in pylint_django.transforms.fields, several fields are hardcoded in a similar fashion:
_STR_FIELDS = ('CharField', 'SlugField', 'URLField', 'TextField', 'EmailField',
'CommaSeparatedIntegerField', 'FilePathField', 'GenericIPAddressField',
'IPAddressField', 'RegexField', 'SlugField')
Further below, a suspiciously named function apply_type_shim, adds information to the class based on the type of field it is (either 'str', 'int', 'dict', 'list', etc.)
This additional information is passed to inference_tip, which according to the astroid docs, is used to add inference info (emphasis mine):
astroid can be used as more than an AST library, it also offers some
basic support of inference, it can infer what names might mean in a
given context, it can be used to solve attributes in a highly complex
class hierarchy, etc. We call this mechanism generally inference
throughout the project.
astroid is the underlying library used by Pylint to represent Python code, so I'm pretty sure that's how the information gets passed to Pylint. If you follow what happens when you import the plugin, you'll find this interesting bit in pylint_django/.plugin, where it actually imports the transforms, effectively adding the inference tip to the AST node.
I think if you want to achieve the same with your own classes, you could either:
Directly derive from another Django model class that already has the associated type you're looking for.
Create, and register an equivalent pylint plugin, that would also use Astroid to add information to the class so that Pylint know what to do with it.
I thought initially that you use a plugin pylint-django, but maybe you explicitly use prospector that automatically installs pylint-django if it finds Django.
The checker pylint neither its plugin doesn't check the code by use information from Python type annotations (PEP 484). It can parse a code with annotations without understanding them and e.g. not to warn about "unused-import" if a name is used in annotations only. The message unsupported-membership-test is reported in a line with expression something in object_A simply if the class A() doesn't have a method __contains__. Similarly the message unsubscriptable-object is related to method __getitem__.
You can patch pylint-django for your custom fields this way:
Add a function:
def my_apply_type_shim(cls, _context=None): # noqa
if cls.name == 'MyListField':
base_nodes = scoped_nodes.builtin_lookup('list')
elif cls.name == 'MyDictField':
base_nodes = scoped_nodes.builtin_lookup('dict')
else:
return apply_type_shim(cls, _context)
base_nodes = [n for n in base_nodes[1] if not isinstance(n, nodes.ImportFrom)]
return iter([cls] + base_nodes)
into pylint_django/transforms/fields.py
and also replace apply_type_shim by my_apply_type_shim in the same file at this line:
def add_transforms(manager):
manager.register_transform(nodes.ClassDef, inference_tip(my_apply_type_shim), is_model_or_form_field)
This adds base classes list or dict respectively, with their magic methods explained above, to your custom field classes if they are used in a Model or FormView.
Notes:
I thought also about a plugin stub solution that does the same, but the alternative with "prospector" seems so complicated for SO that I prefer to simply patch the source after installation.
Classes Model or FormView are the only classes created by metaclasses, used in Django. It is a great idea to emulate a metaclass by a plugin code and to control the analysis simple attributes. If I remember, MyPy, referenced in some comment here, has also a plugin mypy-django for Django, but only for FormView, because writing annotations for django.db is more complicated than to work with attributes. - I was trying to work on it for one week.

Accessing 't' (from r18n) in a rack-unit test of a Sinatra app

When using sinatra-r18n to handle internationalisation, the r18n lib exposes a variable t for use within your helpers, routes and templates, as per these instructions.
I have written a simple unit test using rack-unit to confirm that some of my pluralisations work but the test throws an error claiming t is nil.
I've tried referencing it via app.t, MySillyApp.t (where MySillyApp is the name of my Sinatra app), MySillyApp.settings.t etc and none of them give me access to the t I need.
What I am trying to achieve is a confirmation that my translation files include all the keys I need corresponding to plurals of various metric units my app needs to understand. Perhaps there is a more direct way of testing this without going via the Sinatra app itself. I'd welcome any insight here.
I had similar task to check localized strings in my Cucumber scenarios.
I've made working example.
Here you can find how strings got translated.
This file halps to understand how to add R18n support to your testing framework:
require 'r18n-core'
...
class SinCucR18nWorld
...
include R18n::Helpers
end
As you can see instead of rack/unit I'm using RSpec/Cucumber, sorry.

Django-tastypie creating a URL hierarchy

I'd like to create a URL hierarchy using Tastypie but am running into some errors. Here's how I'd like the hierarchy to work:
/recipe
/recipe/ID
/recipe/ID/spice
/recipe/ID/spice/ID
I can't find out how to do this. When I set this up following the Tastypi instructions my URLs would be like this:
/recipe
/recipe/ID
/spice
/spice/ID
If I change the resource_name for spice to "/recipe/spice" then I get a "NotFound: Invalid resource lookup data provided (mismatched type)" error.
Any suggestions about what I could do?
Tastypie is meant to help implement a REST API, and thus by default only supports URLs that conform to REST practices. Namely, each URL should contain a resource name ('recipe' or 'spice') and optionally an identifier for that resource ('ID'). Anything outside of this breaks from REST practices and if you're not implementing a REST API you may want to re-consider whether or not you should be using Tastypie.
That being said, Tastypie does provide a ton of hooks for customizing things. For custom URLs, you'll want to define the method override_urls to map certain URLs to custom views and do some pre-processing before sending it to the regular dispatchers.
If possible, I'd recommend just using standard REST practices and break things up as separate 'recipe' and 'spice' resources. If you need to filter on recipes based on spices that are in them, 'spices' should be passed in as a GET parameter rather than part of the base URL. Hope that helps.

Opinion: Where to put this code in django app:

Trying to figure out the best way to accomplish this. I have inhereted a Django project that is pretty well done.
There are a number of pre coded modules that a user can include in a page's (a page and a module are models in this app) left well in the admin (ie: side links, ads, constant contact).
A new requirement involves inserting a module of internal links in the same well. These links are not associated with a page in the same way the other modules, they are a seperate many to many join - ie one link can be reused in a set across all the pages.
the template pseudo code is:
if page has modules:
loop through modules:
write the pre coded content of module
Since the links need to be in the same well as the modules, I have created a "link placeholder module" with a slug of link-placeholder.
The new pseudo code is:
if page has modules:
loop through modules:
if module.slug is "link-placeholder":
loop through page.links and output each
else:
write pre-coded module
My question is where is the best place to write this output for the links? As I see it, my options are:
Build the out put in the template (easy, but kind of gets messy - code is nice and neat now)
Build a function in the page model that is called when the "link placeholder is encountered) page.get_internal_link_ouutput. Essentially this would query, build and print internal link module output.
Do the same thing with a custom template tag.
I am leaning towards 2 or 3, but it doesn't seem like the right place to do it. I guess I sometimes get a little confused about the best place to put code in django apps, though I do really like the framework.
Thanks in advance for any advice.
I'd recommend using a custom template tag.
Writing the code directly into the template is not the right place for that much logic, and I don't believe a model should have template-specific methods added to it. Better to have template-specific logic live in template-specific classes and functions (e.g. template tags).