{"id":20467041,"url":"https://github.com/felipepaes/proxyid","last_synced_at":"2026-04-12T20:32:38.164Z","repository":{"id":57455211,"uuid":"346024334","full_name":"felipepaes/proxyid","owner":"felipepaes","description":"Proxyid hides your Django model's primary key","archived":false,"fork":false,"pushed_at":"2021-06-24T23:41:25.000Z","size":106,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-16T14:51:37.200Z","etag":null,"topics":["django","hashids","primary-key"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/felipepaes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-03-09T13:57:35.000Z","updated_at":"2022-07-18T17:08:59.000Z","dependencies_parsed_at":"2022-09-10T00:40:40.225Z","dependency_job_id":null,"html_url":"https://github.com/felipepaes/proxyid","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felipepaes%2Fproxyid","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felipepaes%2Fproxyid/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felipepaes%2Fproxyid/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felipepaes%2Fproxyid/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/felipepaes","download_url":"https://codeload.github.com/felipepaes/proxyid/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242031303,"owners_count":20060579,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["django","hashids","primary-key"],"created_at":"2024-11-15T13:26:54.371Z","updated_at":"2026-04-12T20:32:33.119Z","avatar_url":"https://github.com/felipepaes.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Proxyid   \n\nA Django utility to hide the primary key of a given model. \n\n![PyPI](https://img.shields.io/pypi/v/proxyid)\n![PyPI - Python Version](https://img.shields.io/pypi/pyversions/proxyid)\n![PyPI - Django Version](https://img.shields.io/pypi/djversions/proxyid)\n![PyPI - License](https://img.shields.io/pypi/l/proxyid)\n\n\n[EN](#quick-start) | [PT](#início-rápido)\n\n\nProxyid turns **`https://myapp.com/model/1`** into **`https://myapp.com/model/5NxJD1dG6V`**\n\nProxyid makes use of the [hashids library](https://hashids.org) to mask your integer or uuid based primary keys with a facade, proxy, mask. It's plug'n play, therefore, it doesn't interfere with the database or model definitions.\n\n| Type    | Primary Key                              | Exposed Proxied PK           |\n| :------ | :--------------------------------------- | :--------------------------- |\n| Integer | 3                                        | 5NxJD1dG6VB3ZR3eKyzYEWrba    |\n| UUID    | 82df2e8e-553b-4330-bd46-8299ec67a9bb\t | 7ljjRD1qVLfjkQepdRZAimyDDZZ2 |\n\nPlease, check the following [demo](https://rydder.pythonanywhere.com/)\n\n## Quick Start\n\nAssuming a Django project is already set with an app called appmock, proxyid can be installed with **pip**.\n\n```terminal\n$ pip install proxyid\n```\n\nThe configuration is set as a constant `PROXYID` in `settings.py`\n\n```python\nPROXYID = {\n    \"hashids\": {\n        \"salt\": \"A grain of salt\", # this is your salt\n        \"min_length\": 15           # this is the minimum length of the proxied id\n    }\n}\n```\n\nLet's say the project has an Author model\n\n```python\n# djangoproject/appmock/models.py\nfrom django.db import models\n\nclass Author(models.Model):\n    name = models.CharField()\n    nationality = models.CharField()\n\n    def __str__(self):\n        return self.name\n```\n\nNow take a look at our `urls.py`\n\n```python\n# djangoproject/appmock/urls.py\nfrom django.urls import path\nfrom appmock import views\n\n\nurlpatterns = [\n    # ...other path configuration\n    # ...other path configuration\n    # ...other path configuration\n    path(\"author/\u003cpk\u003e/\", views.author_detail, name=\"author-detail\")\n]\n```\n\n### Proxify the Primary Key\n\nIf the app is exposing the database's primary key, the Author resource would be found, for example, at `http://myapp.com/author/1`\nLet's hide our primary key. by importing the `proxify` decorator and defining a property method.\n\n\n```python\n# djangoproject/appmock/models.py\nfrom django.db import models\nfrom proxyid.decorators import proxify\n\nclass Author(models.Model):\n    name = models.CharField()\n    nationality = models.CharField()\n\n    @property\n    @proxify\n    def id_(self): pass\n\n    def __str__(self):\n        return self.name\n```\n\nThat's it, now our model instance will have the `id_` property with it's unique primary key encoded by proxyid by using the hashids library. All we need  is a method which doesn't return anything and the decorators `@property` and `@proxify`. You can name this property method whatever you want(except **pk** or **id**), let's name it `id_` for this example.\n\nLet's check it by retrieving a model in a django shell session\n\n```terminal\n$ python manage.py shell\nPython 3.9.2 (default, Mar 21 2021, 20:35:03)\n[GCC 9.3.0] on linux\nType \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n(InteractiveConsole)\n\u003e\u003e\u003e from appmock import models\n\u003e\u003e\u003e author = models.Author.object.create(name=\"Lima Barreto\", nationality=\"Brazil\")\n\u003e\u003e\u003e author.id\n1\n\u003e\u003e\u003e author.id_\nRvBykxK6qojOJnOMrQeGpALDW\n```\n\n### Retrieving objects from encoded Primary Keys\n\nNow, how about retrieving our object from the database if our user is giving us the encoded(`RvBykxK6qojOJnOMrQeGpALDW`) primary key?\nLet's go to our hypothetical `author_detail` view function in `views.py`\n\n```python\n# djangoprojects/appmock/views.py\nfrom django.shortcuts import render, HttpResponse\n\nfrom appmock.models import Author\n\nfrom proxyid.encoding import decode\n\n# ...other code\n\ndef author_detail(request, pk):\n    decoded_pk = decode(pk) # this will bring RvBykxK6qojOJnOMrQeGpALDW back to 1\n    author = Author.objects.get(pk=decoded_pk)\n    context = {\"author\" : author}\n    return render(request, \"appmock/author_detail.html\", context)\n\n```\n\nWe imported `decode` from `proxyid.encoding`, the `decode` function will transform our proxied value back to it's original primary key value, allowing us to retrieve our object by giving the pk value to the ORM.\n\nHow the urls were generated? By just passing the object `id_` instead of `pk` property or whatever name you have it to the url function. Like this:\n\n```django-templates\n\u003c!-- some html --\u003e\n\n{% url 'author-detail' author.id_ %}\n```\n\nNow our author resource can be found at `http:myapp.com/author/RvBykxK6qojOJnOMrQeGpALDW`\n\n### What about class based views?\n\nLet's build the same logic of `author_detail` function view as a class based view now:\n\n```python\n# djangoproject/appmock/views.py\nfrom django.views import generic\n\nfrom appmock.models import Author\n\nfrom proxyid.mixins import ProxyidMixin\n\nclass AuthorDetailView(ProxyidMixin, generic.DetailView):\n    template_name = \"appmock/author_detail.html\"\n    model = Author\n    context_object_name = \"author\"\n```\n\nThat's it, the view will work the same way as long as you use the `ProxyidMixin` as a parent class, and don't forget to provide a `pk` argument(this can be customized) from the url dispatcher.\n\n\n\n----\n\n\nUma ferramenta baseado em Django para esconder a chave primária de um dado modelo.\n\nProxyid transforma **`https://meuapp.com/modelo/1`** em **`https://meuapp.com/modelo/5NxJD1dG6V`**\n\nProxyid utiliza a [biblioteca hashids](https://hashids.org) para codificar chaves primárias (int ou uuid). Como solução plug'n play, não interfere com a camada de banco de dados ou definição de modelos.\n\n| Tipo    | Chave Primária                           | Chave Exposta pelo Proxyid   |\n| :------ | :--------------------------------------- | :--------------------------- |\n| Integer | 3                                        | 5NxJD1dG6VB3ZR3eKyzYEWrba    |\n| UUID    | 82df2e8e-553b-4330-bd46-8299ec67a9bb\t | 7ljjRD1qVLfjkQepdRZAimyDDZZ2 |\n\nPor favor, cheque a seguinte [demo](https://rydder.pythonanywhere.com/)\n\n## Início Rápido\n\nConsiderando que um projeto Django já esteja configurado com um app chamado **appmock**, proxyid poder ser instalado via **pip**\n\n```terminal\n$ pip install proxyid\n```\n\nA configuração é aplicada em uma constante `PROXYID` no arquivo `settings.py`\n\n```python\nPROXYID = {\n    \"hashids\": {\n        \"salt\": \"Uma pitada de sal\", # esse é o sal\n        \"min_length\": 15             # esse é o tamanho mínimo das ids geradas\n    }\n}\n```\n\nDigamos que o projeto possua um modelo Author\n\n```python\n# djangoproject/appmock/models.py\nfrom django.db import models\n\nclass Author(models.Model):\n    name = models.CharField()\n    nationality = models.CharField()\n\n    def __str__(self):\n        return self.name\n```\n\nAgora, vejamos nosso `urls.py`\n\n```python\n# djangoproject/appmock/urls.py\nfrom django.urls import path\nfrom appmock import views\n\n\nurlpatterns = [\n    # ...outras configurações path\n    # ...outras configurações path\n    # ...outras configurações path\n    path(\"author/\u003cpk\u003e/\", views.author_detail, name=\"author-detail\")\n]\n```\n\n### Escondendo nossa Chave Primária\n\nCaso o app esteja expondo a chave primária do banco de ados, o modelo Author seria encontrado, por exemplo, em `http://meusite.com/autor/1`. Vamos esconder nossa chave primária, importando o decorator `proxify` e definindo um método propriedade.\n\n\n```python\n# djangoproject/appmock/models.py\nfrom django.db import models\nfrom proxyid.decorators import proxify\n\nclass Author(models.Model):\n    name = models.CharField()\n    nationality = models.CharField()\n\n    @property\n    @proxify\n    def id_(self): pass\n\n    def __str__(self):\n        return self.name\n```\n\nPronto, agora as instâncias de nosso modelo terão a propriedade `id_` com sua chave primária única codificada pelo proxyid, utilizando a biblioteca hashids. Tudo que precisamos foi de um método que retorna nada, e os decoradores `@property` e `@proxify`. Você pode nomear esse método como preferir (com exceção para **pk** ou **id**), o chamaremos de `id_` para este exemplo.\n\nVamos testar nosso modelo iniciando uma sesssão shell no Django.\n\n```terminal\n$ python manage.py shell\nPython 3.9.2 (default, Mar 21 2021, 20:35:03)\n[GCC 9.3.0] on linux\nType \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n(InteractiveConsole)\n\u003e\u003e\u003e from appmock import models\n\u003e\u003e\u003e author = models.Author.object.create(name=\"Lima Barreto\", nationality=\"Brazil\")\n\u003e\u003e\u003e author.id\n1\n\u003e\u003e\u003e author.id_\nRvBykxK6qojOJnOMrQeGpALDW\n```\n\n### Buscando objetos através de uma Chave Primária codificada\n\nAgora, como buscar objects em nosso banco de dados, se nosso usuário estará acessando uma url com a chave primário codificada(`RvBykxK6qojOJnOMrQeGpALDW`)? Vamos para nossa hipotética função view chamada `author_detail` localizada em `views.py`.\n\n\n```python\n# djangoprojects/appmock/views.py\nfrom django.shortcuts import render, HttpResponse\n\nfrom appmock.models import Author\n\nfrom proxyid.encoding import decode\n\n# ...other code\n\ndef author_detail(request, pk):\n    decoded_pk = decode(pk) # isso trará RvBykxK6qojOJnOMrQeGpALDW devolta para 1\n    author = Author.objects.get(pk=decoded_pk)\n    context = {\"author\" : author}\n    return render(request, \"appmock/author_detail.html\", context)\n\n```\n\nImportamos a função `decode` de `proxyid.encoding`, a função `decode` transformará nosso valor codificado devolta para seu valor de chave primária original . permitindo que busquemos nosso objeto com a chave primária original.\n\nComo as urls foram geradas? Simplesmente passando o atributo `id_` da instância do objeto Author ou seja lá qual for o nome da propriedade do seu modelo como argumento para a função url:\n\n```django-templates\n\u003c!-- some html --\u003e\n\n{% url 'author-detail' author.id_ %}\n```\n\nAgora nosso autor pode ser encontrado em `http:myapp.com/author/RvBykxK6qojOJnOMrQeGpALDW`\n\n### E as views baseadas em classes hein, e as classes?\n\nVmoas construir uma view com a mesma lógica daquela função `author_detail`, mas agora com views baseadas em classe:\n\n```python\n# djangoproject/appmock/views.py\nfrom django.views import generic\n\nfrom appmock.models import Author\n\nfrom proxyid.mixins import ProxyidMixin\n\nclass AuthorDetailView(ProxyidMixin, generic.DetailView):\n    template_name = \"appmock/author_detail.html\"\n    model = Author\n    context_object_name = \"author\"\n```\n\nPronto, essa view funcionará da mesma maneira, desde que herde de ProxyidMixin e a sua url providencie um argumento nomeado como `pk`.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffelipepaes%2Fproxyid","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffelipepaes%2Fproxyid","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffelipepaes%2Fproxyid/lists"}