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
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
Simple tagging for django

django-taggit This is a Jazzband project. By contributing you agree to abide by the Contributor Code of Conduct and follow the guidelines. django-tagg

Jazzband 3k Jan 02, 2023
A fresh approach to autocomplete implementations, specially for Django. Status: v3 stable, 2.x.x stable, 1.x.x deprecated. Please DO regularely ping us with your link at #yourlabs IRC channel

Features Python 2.7, 3.4, Django 2.0+ support (Django 1.11 (LTS), is supported until django-autocomplete-light-3.2.10), Django (multiple) choice suppo

YourLabs 1.7k Jan 01, 2023
A ToDO Rest API using Django, PostgreSQL and Docker

This Rest API uses PostgreSQL, Docker and Django to implements a ToDo application.

Brenno Lima dos Santos 2 Jan 05, 2022
Django Persistent Filters is a Python package which provide a django middleware that take care to persist the querystring in the browser cookies.

Django Persistent Filters Django Persistent Filters is a Python package which provide a django middleware that take care to persist the querystring in

Lorenzo Prodon 2 Aug 05, 2022
Redia Cache implementation in django.

django-redis Recipe APP Simple Recipe app which shows different kinds off recipe to the user. Why Cache ? Accessing data from cache is much faster tha

Avinash Alanjkar 1 Sep 21, 2022
A Django app for managing robots.txt files following the robots exclusion protocol

Django Robots This is a basic Django application to manage robots.txt files following the robots exclusion protocol, complementing the Django Sitemap

Jazzband 406 Dec 26, 2022
Twitter-clone using Django (DRF) + VueJS

Twitter Clone work in progress 🚧 A Twitter clone project Table Of Contents About the Project Built With Getting Started Running project License Autho

Ahmad Alwi 8 Sep 08, 2022
Modular search for Django

Haystack Author: Daniel Lindsley Date: 2013/07/28 Haystack provides modular search for Django. It features a unified, familiar API that allows you to

Haystack Search 3.4k Jan 08, 2023
Django Starter is a simple Skeleton to start with a Django project.

Django Starter Template Description Django Starter is a simple Skeleton to start

Numan Ibn Mazid 1 Jan 10, 2022
Django Login Api With Python

How to run this project Download and extract this project Create an environment and install all the libraries from requiements.txt pip freeze -r requi

Vikash Kisku 1 Dec 10, 2021
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
Django URL Shortener is a Django app to to include URL Shortening feature in your Django Project

Django URL Shortener Django URL Shortener is a Django app to to include URL Shortening feature in your Django Project Install this package to your Dja

Rishav Sinha 4 Nov 18, 2021
Simple yet powerful and really extendable application for managing a blog within your Django Web site.

Django Blog Zinnia Simple yet powerful and really extendable application for managing a blog within your Django Web site. Zinnia has been made for pub

Julien Fache 2.1k Dec 24, 2022
Hotwired/Turbo Django response helpers

This package provides helpers for server-side rendering of Hotwired/Turbo streams and frames. Disclaimer: the Hotwired/Turbo client libraries are, at

Hotwire for Django 66 Apr 07, 2022
Auto-detecting the n+1 queries problem in Python

nplusone nplusone is a library for detecting the n+1 queries problem in Python ORMs, including SQLAlchemy, Peewee, and the Django ORM. The Problem Man

Joshua Carp 837 Dec 29, 2022
Packs a bunch of smaller CSS files together from 1 folder.

Packs a bunch of smaller CSS files together from 1 folder.

1 Dec 09, 2021
📝 Sticky Notes in Django admin

django-admin-sticky-notes Share notes between superusers. Installation Install via pip: pip install django_admin_sticky_notes Put django_admin_sticky_

Dariusz Choruży 7 Oct 06, 2021
A calendaring app for Django. It is now stable, Please feel free to use it now. Active development has been taken over by bartekgorny.

Django-schedule A calendaring/scheduling application, featuring: one-time and recurring events calendar exceptions (occurrences changed or cancelled)

Tony Hauber 814 Dec 26, 2022
A Django GraphQL (Graphene) base template

backend A Django GraphQL (Graphene) base template Make sure your IDE/Editor has Black and EditorConfig plugins installed; and configure it lint file a

Reckonsys 4 May 25, 2022