Giter Club home page Giter Club logo

Comments (3)

nshafer avatar nshafer commented on July 18, 2024

First, a disclaimer: THIS IS NOT SUPPORTED AT ALL. Do this at your own risk.

It is possible to monkey-patch a Model from a third-party module. However, since the rest of the module was not written with this in mind, this could have weird unintended side-effects, and go horribly wrong in seriously devious and un-obvious ways. However, I couldn't help myself trying to figure out how to do it.

So this seems to be accomplishable by doing these things:

  1. Import the Model you want to modify somewhere in code that executes at Django startup. For example, in a models.py file or the ready() function of an AppConfig.
  2. Get a reference to the field instance you want to modify in ModelClass._meta.fields. I only tested with swapping out an AutoField with a HashidAutoField. Swapping an IntegerField with a HashidField should probably also work. Swapping out any other kind of field (like CharField) will probably go horribly wrong.
  3. Swap out the __class__ of that instance with HashidAutoField.
  4. Set up the attributes that HashidAutoField expects... the stuff that's normally set in the __init__(). You're going to have to do this manually, as AutoField.__init__() was already called. Hashid*Field expects salt, min_length, alphabet and allow_int_lookups to be set in the current version. This could change in the future, and you would need to adjust your monkey-patch.
  5. TEST... and in fact, I wouldn't recommend doing this in production.
from django.conf import settings
from django.contrib.flatpages.models import FlatPage
from hashids import Hashids
from hashid_field import HashidAutoField

field = FlatPage._meta.fields[0]
field.__class__ = HashidAutoField
field.salt = settings.HASHID_FIELD_SALT
field.min_length = 7
field.alphabet = Hashids.ALPHABET
field.allow_int_lookup = True

There definitely seems to be a problem where ./manage.py makemigrations wants to create a new migration for the field. Which may or may not be bad, but it's wanting to save it in site-packages, which seems bad.

So yeah, not really recommended. Proceed at your own risk.

from django-hashid-field.

ivanfr90 avatar ivanfr90 commented on July 18, 2024

Hi!

I want to apply a robust solution in a production environment so this hacky solution could be a big risk with unknown consequences as you say, althought it's another point of view to solve the requirement.
Based on your idea I found a similar approach that could be satisfied with this script utility patch_model.py. I've not testet yet, but it also looks good.

I'm trying to avoid a monkey-patch, but it seems that there not an easy approach like a safe built in django method or pattern so I think that I have three options:

  1. Suggest to the maintainer of the app the implementation of an abstract model. This allow to customize the model.

  2. Create a fork of the app and include the hash-id attribute to the model. I don't like this option because to include only an attribute I have to include the app to my project and modify it. I think that this have to be avoided. An app have to been developed thinking about its universality and adaptability, so it shoud be easy to do small customizations and modifications from your own app.

  3. Apply a tested monkey-patch similar as shown in previous lines.

I'm very grateful with your contribution.

from django-hashid-field.

nshafer avatar nshafer commented on July 18, 2024

Yes, no matter what, monkey-patching (which that script still does) is fraught with peril, and can result in some really weird bugs. Further, there may be other parts of the third-party module that would just fail in weird ways because they expect an AutoField not a HashidAutoField. Most of the time, it would be fine, but for example if they do a isintance(obj.id, int) that would fail, as obj.id would be an instance of Hashid.

Regarding your point 2, though... you don't need to include it in your project. You can fork the repository, make the modifications and check them in, then have pip install it directly from your fork with something like pip install git+https://github.com/yourusername/your_fork_of_project.git. Then you can also merge changes in from upstream relatively easy if there are no conflicts. You can even put git+ in your requirements.txt file.

I don't agree that module authors need to make this kind of modification possible (not even sure how in this case) as that can greatly increase the complexity of the code, and/or increase dependencies which can have issues of its own.

Happy coding!

from django-hashid-field.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.