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
Django app for handling the server headers required for Cross-Origin Resource Sharing (CORS)

django-cors-headers A Django App that adds Cross-Origin Resource Sharing (CORS) headers to responses. This allows in-browser requests to your Django a

Adam Johnson 4.8k Jan 03, 2023
TinyApp - A Python (Django) Full Stack Application for shortening URLs

TinyApp A Python (Django) Full Stack Application for shortening URLs. How to sta

Li Deng 1 Jan 23, 2022
Store model history and view/revert changes from admin site.

django-simple-history django-simple-history stores Django model state on every create/update/delete. This app supports the following combinations of D

Jazzband 1.8k Jan 08, 2023
Simple API written in Python using FastAPI to store and retrieve Books and Authors.

Simple API made with Python FastAPI WIP: Deploy in AWS with Terraform Simple API written in Python using FastAPI to store and retrieve Books and Autho

Caio Delgado 9 Oct 26, 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
Duckiter will Automatically dockerize your Django projects.

Duckiter Duckiter will Automatically dockerize your Django projects. Requirements : - python version : python version 3.6 or upper version - OS :

soroush safari 23 Sep 16, 2021
A Django app that creates automatic web UIs for Python scripts.

Wooey is a simple web interface to run command line Python scripts. Think of it as an easy way to get your scripts up on the web for routine data anal

Wooey 1.9k Jan 08, 2023
Auth module for Django and GarpixCMS

Garpix Auth Auth module for Django/DRF projects. Part of GarpixCMS. Used packages: django rest framework social-auth-app-django django-rest-framework-

GARPIX CMS 18 Mar 14, 2022
Django Course Project - TextCorrector

Django-TextUtils Django Course Project A tool for analyzing text data in Django backend. It is a project where you can do some of the things with you

1 Oct 29, 2021
A simple plugin to attach a debugger in Django on runserver command.

django-debugger A simple plugin to attach a debugger in Django during runserver Installation pip install django-debugger Usage Prepend django_debugger

Sajal Shrestha 11 Nov 15, 2021
Django models and endpoints for working with large images -- tile serving

Django Large Image Models and endpoints for working with large images in Django -- specifically geared towards geospatial tile serving. DISCLAIMER: th

Resonant GeoData 42 Dec 17, 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
Basic Form Web Development using Python, Django and CSS

thebookrain Basic Form Web Development using Python, Django and CSS This is a basic project that contains two forms - borrow and donate. The form data

Ananya Dhulipala 1 Nov 27, 2021
A tool to automatically fix Django deprecations.

A tool to help upgrade Django projects to newer version of the framework by automatically fixing deprecations. The problem When maintaining a Django s

Bruno Alla 155 Dec 14, 2022
Wrapping Raml around Django rest-api's

Ramlwrap is a toolkit for Django which allows a combination of rapid server prototyping as well as enforcement of API definition from the RAML api. R

Jmons 8 Dec 27, 2021
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
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
An example of Django project with basic user functionality and account activation.

Simple Django Login and Registration An example of Django project with basic user functionality. Screenshots Log In Create an account Authorized page

Hussein Sarea 3 Oct 19, 2022
A simple demonstration of integrating a sentiment analysis tool in a django project

sentiment-analysis A simple demonstration of integrating a sentiment analysis tool in a django project (watch the video .mp4) To run this project : pi

2 Oct 16, 2021
Neighbourhood - A python-django web app to help the residence of a given neighborhood know their surrounding better

Neighbourhood A python-django web app to help the residence of a given neighborh

Levy Omolo 4 Aug 25, 2022