How to test Django custom model fields? - django

I am thinking of creating some subclassed Django model fields and distributing them as a package on PyPI. I like to write unit tests for my code (à la TDD), but I'm a bit puzzled as to how I'd write tests for this particular library.
The first thought that came to my mind was to create a Django project that makes use of my subclasses and just use the Django test tools, but that doesn't seem very elegant at all. There's got to be a better way!
Is there a method of somehow bootstrapping Django for this type of thing? I'd appreciate someone pointing me in the right direction. Thanks!

Django itself comes with some tests for field-subclassing; the tests have their own models.py where the custom fields are used. You should get the best impression when you have a look at the actual code yourself!
Addition: To have the models defined in your test package being discovered by django you will have to add your yourapp.test package to INSTALLED_APPS.
Django itself has a built-in mechanism for its own tests to be automatically discovered and added to INSTALLED_APPS.

Related

How to add fields to third party app model?

I'm working on a web page which uses Django-quiz app. When you install the django-quiz, you can create quizes, questions etc. in Admin.
Unfortunately, there is no way, how to assign Quiz to my model Language so I'm looking for a way, how to add field Language into the model Quiz.
I've tried this but it does not work. I've tried already to create a proxy model with additional field but I realised that it is not possible in proxy models.
from quiz.models import Sitting,Quiz
class QuizAddLanguage(models.Model):
quiz = models.OneToOneField(Quiz)
language = models.ForeignKey(Language)
Do you know what to do to add field to third party app model?
For this time, OneToOne should be enough - for each language there will be one quiz
Since its one to one then you can just define the relationship on your own language class, django by default, will provide you the reverse lookup meaning
language_obj.quiz
quiz_obj.language
will both be valid.
Here is a relevant Django ticket, which was closed with a resolution of "wontfix" six years ago:
https://code.djangoproject.com/ticket/14969
I think this comment provides some good information:
Comments gives you the *right* way to handle this problem -- you define an interface, and make the model itself pluggable. Not all Django's contrib apps follow this approach, but that doesn't mean we bake monkeypatching into the core -- we fix the contrib apps.
django.contrib.comments is now a standalone app, but it still makes itself relatively easy to customize. Here is the relevant documentation:
https://django-contrib-comments.readthedocs.io/en/latest/custom.html
If a third party app doesn't make itself easy to customize, I would suggest asking the developer to update it and point them to the above links for examples on how to go about doing it.

How to customized the model of installed app in Django?

Right now I was using django_comments_xtd in my site, but I wanna make modifications to the models.py of the installed app django_comments_xtd, make it customized. I just don't know how. I knew I may use something like subclass, but there is a lot of connections in those classes in the models.py, I just wanna overwrite one of them, so how should I do this?
Unfortunately, using subclasses would be the best scenario in this case. Also you could get a local copy of that app and put it in your project files and edit the source directly. I've had to do this on occasion.
Hopefully that helps!

How to reuse Django tests?

I'm extending Django QuerySet by subclass (say MyQuerySet), and I would like to guarantee that my implementation does not break any existing functionality of QuerySet.
How can I test MyQuerySet against existing Django tests on QuerySet without having to replicate them?
For concreteness, let's consider the example of tests of prefetch_related, found in django/tests/prefetch_related package.
I would like to run all those tests on MyQuerySet. However, those tests are implemented using the default manager of the models in the package. Does anyone have any idea how to e.g. duck type objects to a custom manager that uses MyQuerySet?

Create model just for testing

I have an abstract User model.
The tests include subclassing this abstract model and setting AUTH_USER_MODEL to the subclassed model.
The problem with AUTH_USER_MODEL is it must be of the form "app-name.model-name" and hence it must
refer to a model in a models.py file . But if it is inside a models.py file, it will get sync'ed to production database, which isn't exactly harmful but it would be nice if it isn't so.
I have seen Django: How to create a model dynamically just for testing but the answers seem hackish (and unreliable?)
Currently what I do is:
in [apps]/models.py:
# this model only gets created during a test
if 'test' in sys.argv:
class AccountTest(AbstractAccount):
pass
in [apps]/tests/init.py:
#override_settings(
AUTH_USER_MODEL = '[apps].AccountTest',
)
class AccountManagerTest(TransactionTestCase):
Does anyone have a better way? This feels rather hackish.
Also, any problem with this approach?
A good approach is to use separate settings file for your testing environment. You could have an application that is listed only in the INSTALLED_APPS of these test settings, and implement your test models there. This approach is also good if for example you want to use nose to run your tests etc... Then you should run your tests like this:
python manage.py test --settings=my_project.test_settings

Django design patterns for overriding models

I'm working on an e-commerce framework for Django. The chief design goal is to provide the bare minimum functionality in terms of models and view, instead allowing the users of the library to extend or replace the components with their own.
The reasoning for this is that trying to develop a one-size-fits-all solution to e-commerce leads to overcomplicated code which is often far from optimal.
One approach to tackling this seems to be using inversion-of-control, either through Django's settings file or import hacks, but I've come up against a bit of a problem due to how Django registers its models.
The e-commerce framework provides a bunch of abstract models, as well as concrete versions in {app_label}/models.py. Views make use of Django's get_model(app_label,model) function to return the model class without having to hard-code the reference.
This approach has some problems:
Users have to mimic the structure of the framework's apps, ie the app_label and effectively replace our version of the app with their own
Because of the way the admin site works by looking for admin.py in each installed app, they have to mimic or explicitly import the framework's admin classes in order to use them. But by importing them, the register method gets called so they have to be unregistered if a user wants to customise them.
The user has to be extremely careful about how they import concrete models from the core framework. This is because Django's base model metaclass automatically registers a model with the app cache as soon as the class definition is read (ie upon __new__), and the first model registered with a specific label is the one you're stuck with. So you have to define all your override models BEFORE you import any of the core models. This means you end up with messy situations of having a bunch of imports at the bottom of your modules rather than the top.
My thinking is to go further down the inversion-of-control rabbit hole:
All references to core components (models, views, admin, etc) replaced with calls to an IoC container
For all the core (e-commerce framework) models, replace the use of Django's base model metaclass with one that doesn't automatically register the models, then have the container explicitly register them on startup.
My question:
Is there a better way to solve this problem? The goal is to make it easy to customise the framework and override functionality without having to learn lots of annoying tricks. The key seems to be with models and the admin site.
I appreciate that using an IoC container isn't a common pattern in the Django world, so I want to avoid it if possible, but it is seeming like the right solution.
Did you look at the code from other projects with a similar approach?
Not sure if this way covers your needs, but imo the code of django-shop is worth to look at.
This framework provides the basic logic, allowing you to provide custom logic where needed.
customize via models
eg see the productmodel.py
#==============================================================================
# Extensibility
#==============================================================================
PRODUCT_MODEL = getattr(settings, 'SHOP_PRODUCT_MODEL',
'shop.models.defaults.product.Product')
Product = load_class(PRODUCT_MODEL, 'SHOP_PRODUCT_MODEL')
customize via logic/urls
eg see the shop's simplevariation-plugin
It extends the cart-logic, so it hooks in via urlpattern:
(r'^shop/cart/', include(simplevariations_urls)),
(r'^shop/', include(shop_urls)),
and extends the views:
...
from shop.views.cart import CartDetails
class SimplevariationCartDetails(CartDetails):
"""Cart view that answers GET and POSTS request."""
...
The framework provides several points to hook-in, the simplevariation-plugin mentionned above additionally provides a cart-modifier:
SHOP_CART_MODIFIERS = [
...
'shop_simplevariations.cart_modifier.ProductOptionsModifier',
...
]
I worry that this explanation is not very understandable, it is difficult to briefly summarize this concept. But take a look at the django-shop project and some of its extensions: ecosystem