Django model mixins and utilities.

Overview
Comments
  • Allow FieldTracker on Django user model (and other children of abstract base classes)

    Allow FieldTracker on Django user model (and other children of abstract base classes)

    Problem

    Here is a branch with failing tests that I think should work (and that I think worked in earlier versions?): https://github.com/jazzband/django-model-utils/compare/master...jcushman:abstract-test-failure

    This seems to be related to the stuff that @lucaswiman added in #317. @lucaswiman, I'm hoping based on that work you might have some clever idea for how to fix this. :)

    Here's the situation: you have an abstract base class that defines a static attribute like is_active = True, and a concrete model inheriting from that class that defines a field like is_active = models.BooleanField(default=True). The model then throws an error on save():

    from django.contrib.auth.models import AbstractUser
    
    class MyUser(AbstractUser):
        tracker = FieldTracker()
    
    MyUser().save()
    

    Result:

        def __get__(self, instance, owner):
            if instance is None:
                return self
            was_deferred = self.field_name in instance.get_deferred_fields()
    >       value = self.descriptor.__get__(instance, owner)
    E       AttributeError: 'bool' object has no attribute '__get__'
    
    model_utils/tracker.py:43: AttributeError
    

    It would be great for this to work, because tracking changes on the Django user model is handy.

    Debugging that error, I found the problem boils down to this:

    class AbstractUser(models.Model):
        is_active = True
    
        class Meta:
            abstract = True
    
    class MyUser(AbstractUser):
        is_active = models.BooleanField(default=True)
        tracker = FieldTracker()
    
    MyUser().save()
    

    The reason that fails is https://github.com/jazzband/django-model-utils/blob/master/model_utils/tracker.py#L218 :

    descriptor = getattr(sender, field_name)
    ...
    setattr(sender, field_name, wrapped_descriptor)
    

    ... which boils down to setting MyUser.is_active = DescriptorWrapper(MyUser.is_active). And that doesn't work because you expect MyUser.is_active to start with a value of DeferredAttribute('is_active'), but it actually returns True. For reasons I don't understand, when you override a static attribute on an abstract class, you get the base class's value back instead of the subclass's.

    I tried tweaking tracker.py with variations on descriptor = getattr(sender, field_name) if field_name in sender.__dict__ else DeferredAttribute(field_name), but that broke foreign key fields and feels pretty janky anyway.

    Any ideas on how to get this working?

    Thanks!

    Environment

    • Django Model Utils version: master
    • Django version: 2.1
    • Python version: 3.6
    • Other libraries used, if any:
    opened by jcushman 27
  • Small bug fix and feature addition.

    Small bug fix and feature addition.

    Please note that I have made a choice in the feature addition that people might like to have full downcasting even if the associated select_related isn't available (because of django <1.6 bugs). If you don't like it, feel free to take it out. However, the second part is indeed a bug, if you have multiple grandchildren from a single child, the instance is not the first grandchild checked, but it is a sibling to the grandchild checked, then the child class will be taken instead of continuing on to the other grandchildren.

    • Down-cast to final level even if we can't select the related data (in < 1.6)
    • Fix bug where child classes are accepted if grand-child doesn't match even if there are more grand-child classes to check.

    The second commit is a feature addition to allow casting of related fields (like foreign keys) in what I believe is a query efficient method. I have not yet written unit tests for it, but it does work in the testing I have done (in system testing).

    opened by CrazyCasta 17
  • Feature suggestion: Model mixin for checking for dirty fields

    Feature suggestion: Model mixin for checking for dirty fields

    I'm planning to implement tests and code for a model mixin that keeps track of the original values of the model. I often find this useful for performing tasks in save() methods or pre_save signals (like clearing cache on changes).

    A very simple implementation. Another implementation that supports m2m fields

    I don't think the implementation of this should create any extra DB queries... at least not by default. Feedback on implementation suggestion is welcome.

    Does this sound like a good addition to django-model-utils?

    opened by treyhunner 17
  • Remove Django itself from install_requires

    Remove Django itself from install_requires

    There's an unfortunate side effect of referencing Django itself in setup.py or requirements.txt

    It rather unexpectedly results in an upgrade to Django itself if I type: "pip install django-model-utils -U"

    And really - your app doesn't 'require' django as much as it's an add-on for Django so not much is lost by removing it. Is anyone likely to install django-model-utils and expect it to install Django for them?

    There's a discussion on the same issue here: https://github.com/charettes/django-admin-enhancer/issues/23

    opened by andybak 16
  • Drop unsupported Django versions

    Drop unsupported Django versions

    • Drops support for anything below Django 1.8 (current LTS release)
    • ~~Cleans up some pep8 E303 warnings. I can remove this commit - just went ahead because my editor lit up like a christmas tree.~~
    • ~~Resolves 183~~.
    • Supersedes / closes #162.
    • Supersedes / closes #204.
    opened by rpkilby 15
  • Add django 3.0 to the test matrix and drop six

    Add django 3.0 to the test matrix and drop six

    Problem

    Six won't be used in Django 3.0 so it will cause ImportError

    Solution

    Drop six and add django 3.0 to the test matrix to ensure it is supported

    Commandments

    • [x] Write PEP8 compliant code.
    • [x] Cover it with tests.
    • [x] Update CHANGES.rst file to describe the changes, and quote according issue with GH-<issue_number>.
    • [x] Pay attention to backward compatibility, or if it breaks it, explain why.
    • [x] Update documentation (if relevant).
    opened by mvbrn 14
  • preserve reverse_related_field caches when casting to a subclass

    preserve reverse_related_field caches when casting to a subclass

    I was going to write a test for this but the tests currently fail up to 4 assertions when I run them without making a change. Anyway, I'm new at this whole pull thing so be gentle.

    The issue is if i define a class with a related class:

    class Opportunity(models.Model):
        objects=InheritanceManager()
        pass
    
    class Contest(Opportunity):
        pass
    
    class Terms(models.Model):
        opportunity = models.OneToOneField(Opportunity, related_name='contest_terms')
    

    Calling:

    contests = Opportunity.objects.select_related('contest_terms').filter(id=1)
    t = contests[0].contest_terms
    assert(len(connection.queries)==1)
    

    works because it makes one DB hit and can access the contest_terms as it's been cached by select_related() changing the query in the first line to include select_subclasses:

    contests = Opportunity.objects.select_related('contest_terms').select_subclasses('contest').filter(id=1)
    

    fails because the related object cache is lost after subclassing so it makes the additional hit to the DB to get the terms.

    The fix I proposed will copy the object caches from the base class when _get_sub_obj_recurse finds the appropriate subclass. This will keep the results of select_related() in the returned model instance.

    opened by screamndigit 12
  • Json fields support

    Json fields support

    This improvement will be useful for those who uses the field to store small or medium json-data sets. It is unlikely that the field will store complex data with a high level of nesting (for such problems it's better to use NoSQL), so the overhead of using deepcopy will be negligible, especially given the fact that the protective function (prevent_side_effects) will be called only during initialization. For models without json-fields only one extra loop will be made through the fields during initialization.

    opened by silonov 12
  • Adding ppc64le architecture support on travis-ci

    Adding ppc64le architecture support on travis-ci

    Hi, I had added ppc64le(Linux on Power) architecture support on travis-ci and looks like its been successfully added. I believe it is ready for the final review and merge. Travis-CI build job: https://travis-ci.com/github/kishorkunal-raj/django-model-utils/builds/188852916

    Please have a look.

    Thanks!! Kishor Kunal Raj

    opened by kishorkunal-raj 11
  • Fix handling of deferred fields on django 1.10+

    Fix handling of deferred fields on django 1.10+

    Fixes #278. cc @utapyngo @djstein

    Problem

    Prior to Django 1.10, deferred attributes were handled by constructing a new model class with custom descriptors for the deferred attributes. After 1.10, deferred fields are tracked by whether the attribute is present in the instance __dict__.

    FieldTracker handled tracking on these fields by overwriting the descriptors on the model class. This means that in 1.10+, the instance model class is the model, so FieldTracker can introduce changes to the base class whenever deferred fields are used that persist on other queries. #278 This is reproduced in a test case.

    Solution

    I updated the finalize_class method to wrap field descriptors. This preserves the custom descriptor behavior, and means that deferring fields does not lead to permanent changes in base model classes. This is only done for django versions after 1.10: the previous behavior is preserved for 1.8 and 1.9.

    Since the relevant code branches behavior on unsupported versions of Django, I also removed all branching behavior for versions of django listed as unsupported in the CHANGELOG.

    Commandments

    • [ ] Write PEP8 compliant code.
    • [x] Cover it with tests. Reproduced in test cases, which fail prior to 54cc1507a79460497d40f6cba779f67a4b5f8041 and pass afterwards.
    • [x] Update CHANGES.rst file to describe the changes, and quote according issue with GH-<issue_number>.
    • [x] Pay attention to backward compatibility, or if it breaks it, explain why. The only backwards incompatible change is that the tracker._deferred_fields attribute is not set on django versions >=1.10. Since _deferred_fields is a private attribute, I wouldn't consider this a breaking change.
    • [x] Update documentation (if relevant). _I don't think it is relevant.

    Regarding PEP8, I ran flake8, and it generated a number of errors. I think my code didn't introduce new PEP8 violations, but I'm not sure. If you want, I can submit a separate PR fixing all the PEP8 violations, and rebase onto this branch.

    opened by lucaswiman 11
  • Implemented ability to lie about modified fields

    Implemented ability to lie about modified fields

    This would be a first stab at the changes I was describing in #109, to allow for manually setting the modified attributes of a TimeStampedModel (or, really, the fields backing that model)

    • Are there any other Django API methods that need demonstrating?
    • Changelog/docs would need updating.
    opened by kezabelle 11
  • Add type hints and the py.typed stub

    Add type hints and the py.typed stub

    Problem

    Model utils does not include type hints and py.typed. This prevents tools such as mypy to work properly with it.

    Solution

    Add model_utils/py.typed and a few typing hints.

    Commandments

    • [x] Write PEP8 compliant code.
    • [_] Cover it with tests.
    • [_] Update CHANGES.rst file to describe the changes, and quote according issue with GH-<issue_number>.
    • [x] Pay attention to backward compatibility, or if it breaks it, explain why.
    • [_] Update documentation (if relevant).
    opened by fabiommendes 0
  • Get sublcass queryset only

    Get sublcass queryset only

    I can't get queryset for a particular subclass only. I want to get only products relating that subclass only

    • Django Model Utils version: 4.3.1
    • Django version: 4.1
    • Python version: 3.9
    class Product(models.Model)
    ...
    objects  = InheritanceManager()
    
    
    class Phone(Product)
    ...
    
    class Laptop(Product)
    ...
    

    How do I get querysets for the subclass Phone without any other subclasses instances I have gone through the documentation and didn't find any

    I have built a custom filter that can do but it means I don't need the package and my concern is scalability of the custom implementation. I want to know if the package can help so I don't have to reinvent the wheel.

    opened by KekeliDev 2
  • Add support for Python 3.11

    Add support for Python 3.11

    Problem

    Python 3.11 was released on 2022-10-24 🚀

    image

    We should test it and declare support via the Trove classifier.

    Solution

    Add to tox.ini for local and CI testing, add to GitHub Actions for CI, and add the Trove classifier to declare support.

    Also bump GitHub Actions and add colour to CI logs for readability.

    Commandments

    • [x] Write PEP8 compliant code.
    • [x] Cover it with tests.
    • [x] Update CHANGES.rst file to describe the changes, and quote according issue with GH-<issue_number>.
    • [x] Pay attention to backward compatibility, or if it breaks it, explain why.
    • [x] Update documentation (if relevant).
    opened by hugovk 1
  • Adding async support to `InheritanceManager`/`InheritanceQuerySet`

    Adding async support to `InheritanceManager`/`InheritanceQuerySet`

    Problem

    Hey, since Django ORM is starting to support async more and more, I'm wondering if you guys thought about adding async support to InheritanceManager (and InheritanceQuerySet respectively)?

    Environment

    • Django Model Utils version: 4.2.0
    • Django version: 4.1
    • Python version: 3.10
    • Other libraries used, if any: not-relevant

    Code examples

    So far I was thinking of primitive solution to this problem and I've ended up with something like this, but I have not tested it yet (hopefully will get to testing it in few days). Do you think it should work, or is there some bigger problem about integrating async support to InheritanceManager?

    class ExtendedInheritanceQuerySet(InheritanceQuerySet):
        """InheritanceQuerySet from django-model-utils extended for async methods."""
    
        async def aselect_subclasses(self, *subclasses):
            return await sync_to_async(self.select_subclasses)(*subclasses)
    
        async def aget_subclass(self, *args, **kwargs):
            return await sync_to_async(self.get_subclass)(*args, **kwargs)
    
    
    class ExtendedInheritanceManager(InheritanceManager):
        """InheritanceManager from django-model-utils extended for async methods."""
    
        # todo also possible to create manager dynamically using `from_queryset` or `as_manager`
    
        _queryset_class = ExtendedInheritanceQuerySet
    
        async def aselect_subclasses(self, *subclasses):
            return await self.get_queryset().aselect_subclasses(*subclasses)
    
        async def aget_subclass(self, *args, **kwargs):
            return await self.get_queryset().aget_subclass(*args, **kwargs)
    
    opened by microHoffman 0
  • Inheritance improvments: Select subclasses of foreign relations + get subclass of model fields

    Inheritance improvments: Select subclasses of foreign relations + get subclass of model fields

    Problem

    I wanted to do single query SQL selects of foreign key relations that are using Django model inheritance and found the following two improvements helpful.

    Let me know what you think.

    Code examples

    Improvement to InheritanceQuerySet that is able to select inherited fields of foreign key relationship. Note that this works with multi-level inheritance by letting field_name be a tuple of list of names.

    ` class InheritanceQuerySet(ModelUtilsInheritanceQuerySet):

    def select_field_subclasses(self, field_name):
        # Get field name iterable
        if isinstance(field_name, str):
            field_names = (field_name,)
        else:
            field_names = field_name
    
        # Lookup model
        model = self.model
        for field_name in field_names:
            field = model._meta.get_field(field_name)
            model = field.related_model
    
        # Lookup subclasses
        subclasses = self._get_subclasses_recurse(model)
    
        # Construct query
        subclasses = ['%s__%s' % ('__'.join(field_names), subclass) for subclass in subclasses]
    
        return self.select_related(*subclasses)
    

    `

    Using proper select queries with the above method, subclasses of foreign key relations can be retrieved with the following Model Mixin without touching the database.

    ` class InheritanceMixin:

    def get_subclass(self):
        # Lookup subclasses
        helper = InheritanceQuerySetMixin() # hack to re-use private method of mixin
        subclasses = helper._get_subclasses_recurse(self.__class__)
        
        # Look for existing subclass
        for subclass in subclasses:
            try:
                return getattr(self, subclass)
            except getattr(self.__class__, subclass).RelatedObjectDoesNotExist:
                pass
    
        return self
    

    `

    opened by mortenthansen 0
Releases(4.2.0)
  • 4.2.0(Oct 11, 2021)

    • Add support for Django 3.2
    • Drop support for Django 3.0
    • Add support for Python 3.10
    • Added urlsafe token field.
    • Introduce context manager for FieldTracker state reset (GH-#491)
    • Fix performance regression of FieldTracker on FileField subclasses on Django 3.1+ (GH-#498)
    Source code(tar.gz)
    Source code(zip)
  • 4.1.1(Apr 8, 2021)

    • Applied isort to codebase (Refs GH-402)
    • Fix TypeError in save when model inherits from both TimeStampModel and StatusModel. (Fixes GH-465)
    Source code(tar.gz)
    Source code(zip)
  • 4.1.0(Apr 8, 2021)

    • Update InheritanceQuerySetMixin to avoid querying too much tables
    • TimeStampedModel now automatically adds 'modified' field as an update_fields parameter even if it is forgotten while using save()
    • FieldTracker now marks fields as not changed after refresh_from_db
    • FieldTracker now respects update_fields changed in overridden save() method
    • Replace ugettext_lazy with gettext_lazy to satisfy Django deprecation warning
    • Add available_objects manager to SoftDeletableModel and add deprecation warning to objects manager.
    • StatusModel now automatically adds 'status_changed' field during save as an update_fieldsparameter when 'status' is present in it to make sure it is not forgotten.
    • Update test requirements
    • Move tests to GitHub Actions: https://github.com/jazzband/django-model-utils/actions
    • Drop support for Django 2.1
    • Add support for Python 3.9
    • Add support for Django 3.1
    Source code(tar.gz)
    Source code(zip)
  • 4.0.0(Dec 11, 2019)

    4.0.0 (2019-12-11)

    • Remove hacks for previously supported Django versions. (Fixes GH-390)
    • Dropped support for Python 2.7. (Fixes GH-393)
    • Dropped usage of six
    • Drop support for Django 1.11
    • Add support for Python 3.8
    • Add support for Django 3.0
    Source code(tar.gz)
    Source code(zip)
  • 3.1.2(May 9, 2018)

Owner
Jazzband
Jazzband
PostgreSQL with Docker + Portainer + pgAdmin + Django local

django-postgresql-docker Running PostgreSQL with Docker + Portainer + pgAdmin + Django local for development. This project was done with: Python 3.9.8

Regis Santos 4 Jun 12, 2022
Keep track of failed login attempts in Django-powered sites.

django-axes Axes is a Django plugin for keeping track of suspicious login attempts for your Django based website and implementing simple brute-force a

Jazzband 1.1k Dec 30, 2022
REST API con Python, Django y MySQL (GET, POST, PUT, DELETE)

django_api_mysql REST API con Python, Django y MySQL (GET, POST, PUT, DELETE) REST API con Python, Django y MySQL (GET, POST, PUT, DELETE)

Andrew 1 Dec 28, 2021
django-reversion is an extension to the Django web framework that provides version control for model instances.

django-reversion django-reversion is an extension to the Django web framework that provides version control for model instances. Requirements Python 3

Dave Hall 2.8k Jan 02, 2023
A simple Django dev environment setup with docker for demo purposes for GalsenDev community

GalsenDEV Docker Demo This is a basic Django dev environment setup with docker and docker-compose for a GalsenDev Meetup. The main purposes was to mak

3 Jul 03, 2021
This is raw connection between redis server and django python app

Django_Redis This repository contains the code for this blogpost. Running the Application Clone the repository git clone https://github.com/xxl4tomxu9

Tom Xu 1 Sep 15, 2022
Fast / fuzzy PostgreSQL counts for Django

Created by Stephen McDonald Introduction Up until PostgreSQL 9.2, COUNT queries generally required scanning every row in a database table. With millio

stephenmcd 85 Oct 25, 2021
A package to handle images in django

Django Image Tools Django Image Tools is a small app that will allow you to manage your project's images without worrying much about image sizes, how

The Bonsai Studio 42 Jun 02, 2022
Yummy Django API, it's the exclusive API used for the e-yummy-ke vue web app

Yummy Django API, it's the exclusive API used for the e-yummy-ke vue web app

Am.Chris_KE 1 Feb 14, 2022
Django-Audiofield is a simple app that allows Audio files upload, management and conversion to different audio format (mp3, wav & ogg), which also makes it easy to play audio files into your Django application.

Django-Audiofield Description: Django Audio Management Tools Maintainer: Areski Contributors: list of contributors Django-Audiofield is a simple app t

Areski Belaid 167 Nov 10, 2022
Learn Python and the Django Framework by building a e-commerce website

The Django-Ecommerce is an open-source project initiative and tutorial series built with Python and the Django Framework.

Very Academy 275 Jan 08, 2023
open source online judge based on Vue, Django and Docker

An onlinejudge system based on Python and Vue

Qingdao University(青岛大学) 5.2k Jan 09, 2023
With Django Hijack, admins can log in and work on behalf of other users without having to know their credentials.

Django Hijack With Django Hijack, admins can log in and work on behalf of other users without having to know their credentials. Docs 3.x docs are avai

1.2k Jan 05, 2023
A app for managing lessons with Django

Course Notes A app for managing lessons with Django Some Ideas

Motahhar.Mokfi 6 Jan 28, 2022
A handy tool for generating Django-based backend projects without coding. On the other hand, it is a code generator of the Django framework.

Django Sage Painless The django-sage-painless is a valuable package based on Django Web Framework & Django Rest Framework for high-level and rapid web

sageteam 51 Sep 15, 2022
Django Livre Bank

Django Livre Bank Projeto final da academia Construdelas. API de um banco fictício com clientes, contas e transações. Integrantes da equipe Bárbara Sa

Cecília Costa 3 Dec 22, 2021
PEP-484 type hints bindings for the Django web framework

mypy-django Type stubs to use the mypy static type-checker with your Django projects This project includes the PEP-484 compatible "type stubs" for Dja

Machinalis 223 Jun 17, 2022
Utility for working with recurring dates in Django.

django-recurrence django-recurrence is a utility for working with recurring dates in Django. Documentation is available at https://django-recurrence.r

408 Jan 06, 2023
Let AngularJS play well with Django

django-angular Let Django play well with AngularJS What does it offer? Add AngularJS directives to Django Forms. This allows to handle client side for

Jacob Rief 1.2k Dec 27, 2022
Streamlining Django forms to provide all the wins of single-page-applications without the pain.

nango Streamlining Django forms to provide all the wins of single-page-applications without the pain. Key features Available to all Django deployments

Nick Farrell 107 Dec 12, 2022