diff --git a/config.yaml b/config.yaml index 039f3d1..d1245b8 100644 --- a/config.yaml +++ b/config.yaml @@ -7,10 +7,8 @@ googleAnalytics: "UA-22087729-1" params: author: "Renne Rocha" - - siteName: "Hugo Tania is Amazing" - siteDesc: "Hugo is Absurdly Fast!" - + siteName: "Sharing what I learn about software development mainly" + siteDesc: "Sharing what I learn about software development mainly" colorScheme: toggle: true @@ -43,7 +41,7 @@ params: menu: header: - - name: Postagens + - name: Articles url: "/articles/" footer: - name: RSS diff --git a/content/posts/20070921-iniciando-ie-powerbuilder.md b/content/posts/20070921-iniciando-ie-powerbuilder.md new file mode 100644 index 0000000..2cc6174 --- /dev/null +++ b/content/posts/20070921-iniciando-ie-powerbuilder.md @@ -0,0 +1,45 @@ +--- +title: "Iniciando o Internet Explorer a partir do PowerBuilder" +publishdate: 2007-09-21 +tags: ["powerbuilder"] +slug: iniciando-ie-com-powerbuilder +--- + +Esta semana tive que iniciar um projeto em que a principal funcionalidade seria executar a partir de um botão em uma window o Internet Explorer na máquina do cliente, abrindo uma determinada URL. Pensei em usar inicialmente a função `Run()`, porém uma das limitações do projeto era que a janela do navegador não poderia ter nenhuma barra de ferramentas disponível (endereço, status, favoritos, etc) + +Como não é possível iniciar o IE em linha de comando com parâmetros para ocultar essas barras de ferramentas tive que procurar outra solução. Pesquisando dentro da empresa, me sugeriram utilizar um objeto OLE para fazer essa tarefa. + +Pesquisando no site do MSDN, descobri o objeto [InternetExplorer](https://learn.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa752084(v=vs.85)?redirectedfrom=MSDN) que permite trabalhar com uma instância do IE. Você pode configurar diversas propriedades desse objeto (como exibição das barras de ferramentas, tamanho da janela, etc). + +Bom, no final fiz o seguinte código (utilizei o PowerBuilder 7) dentro do evento `clicked()` de um botão: + +``` +OLEObject uo_ie +uo_ie = CREATE OLEObject +Integer ii_handleoleobject = -999 + +ii_handleoleobject = uo_ie.ConnectToNewObject("InternetExplorer.Application") +IF ii_handleoleobject < 0 THEN + DESTROY uo_ie + MessageBox('Erro','Não foi ´possível criar o objeto OLE') +ELSE + uo_ie.AddressBar = FALSE + uo_ie.MenuBar = FALSE + uo_ie.Resizable = FALSE + uo_ie.StatusBar = FALSE + uo_ie.ToolBar = FALSE + uo_ie.Visible = TRUE + uo_ie.Left = 200 + uo_ie.Top = 200 + uo_ie.Height = 500 + uo_ie.Width = 500 + uo_ie.Navigate(is_urlchamada) + SetForegroundWindow(uo_ie.HWND) +END IF +``` + +Declarando uma função externa (para que a janela recém-criada fique ativada): + +``` +FUNCTION boolean SetForegroundWindow( long hWnd ) LIBRARY "USER32" +``` diff --git a/content/posts/validando-dados-extraidos-com-scrapy.md b/content/posts/20190308-validando-dados-extraidos-com-scrapy.md similarity index 99% rename from content/posts/validando-dados-extraidos-com-scrapy.md rename to content/posts/20190308-validando-dados-extraidos-com-scrapy.md index 5d52889..dc8d49b 100644 --- a/content/posts/validando-dados-extraidos-com-scrapy.md +++ b/content/posts/20190308-validando-dados-extraidos-com-scrapy.md @@ -2,6 +2,7 @@ title: "Validando dados extraídos com Scrapy" publishdate: 2019-03-08 tags: ["scrapy", "scraping", "monitoramento"] +slug: validando-dados-extraidos-com-scrapy --- Como você garante a qualidade e a confiabilidade dos dados que você está diff --git a/content/posts/monitorando-seus-projetos-de-raspagem-de-dados.md b/content/posts/20220113-monitorando-seus-projetos-de-raspagem-de-dados.md similarity index 99% rename from content/posts/monitorando-seus-projetos-de-raspagem-de-dados.md rename to content/posts/20220113-monitorando-seus-projetos-de-raspagem-de-dados.md index 1e12e5e..ce1bf1d 100644 --- a/content/posts/monitorando-seus-projetos-de-raspagem-de-dados.md +++ b/content/posts/20220113-monitorando-seus-projetos-de-raspagem-de-dados.md @@ -2,6 +2,7 @@ title: "Monitorando seus projetos de raspagem de dados" publishdate: 2022-01-13 tags: ["monitoramento", "scrapy", "raspagem de dados", "python", "spidermon"] +slug: monitorando-seus-projetos-de-raspagem-de-dados --- Quando passamos a extrair dados de uma página com regularidade, com diff --git a/content/posts/revisao-de-codigo-extraindo-dados-do-site-aos-fatos.md b/content/posts/20220408-revisao-de-codigo-extraindo-dados-do-site-aos-fatos.md similarity index 97% rename from content/posts/revisao-de-codigo-extraindo-dados-do-site-aos-fatos.md rename to content/posts/20220408-revisao-de-codigo-extraindo-dados-do-site-aos-fatos.md index b40228b..18772e5 100644 --- a/content/posts/revisao-de-codigo-extraindo-dados-do-site-aos-fatos.md +++ b/content/posts/20220408-revisao-de-codigo-extraindo-dados-do-site-aos-fatos.md @@ -2,6 +2,7 @@ title: "Revisão de Código: Extraindo dados do site 'Aos Fatos'" publishdate: 2022-04-08 tags: ["revisão de código", "scrapy", "raspagem de dados", "python", "live"] +slug: revisao-de-codigo-extraindo-dados-do-site-aos-fatos --- Algumas semanas atrás, fiz a revisão de um código para extrair informações de diff --git a/content/posts/testando-multiplas-chamadas-de-um-mock.md b/content/posts/20221107-testando-multiplas-chamadas-de-um-mock.md similarity index 98% rename from content/posts/testando-multiplas-chamadas-de-um-mock.md rename to content/posts/20221107-testando-multiplas-chamadas-de-um-mock.md index c1568c4..5fc6f72 100644 --- a/content/posts/testando-multiplas-chamadas-de-um-mock.md +++ b/content/posts/20221107-testando-multiplas-chamadas-de-um-mock.md @@ -2,6 +2,7 @@ title: "Testando múltiplas chamadas de uma função com mocks" publishdate: 2022-11-07 tags: ["python", "testes", "pytest"] +slug: testando-multiplas-chamadas-de-um-mock --- Em algumas situações durante o teste e alguma função, queremos confirmar diff --git a/content/posts/sobre-perguntas-muito-vagas.md b/content/posts/20221111-sobre-perguntas-muito-vagas.md similarity index 97% rename from content/posts/sobre-perguntas-muito-vagas.md rename to content/posts/20221111-sobre-perguntas-muito-vagas.md index a041662..fb0e8d7 100644 --- a/content/posts/sobre-perguntas-muito-vagas.md +++ b/content/posts/20221111-sobre-perguntas-muito-vagas.md @@ -2,6 +2,7 @@ title: "Sobre perguntas muito vagas em grupos de discussão" publishdate: 2022-11-11 tags: ["perguntas"] +slug: sobre-perguntas-muito-vagas --- Eu acompanho diversos grupos de tecnologia por email (hoje nem tanto), diff --git a/content/posts/extending-django-user-profile-model.md b/content/posts/20230424-extending-django-user-profile-model.md similarity index 99% rename from content/posts/extending-django-user-profile-model.md rename to content/posts/20230424-extending-django-user-profile-model.md index 2a4d92f..e8f2cc0 100644 --- a/content/posts/extending-django-user-profile-model.md +++ b/content/posts/20230424-extending-django-user-profile-model.md @@ -2,7 +2,7 @@ title: "Extending built-in Django User with a Profile Model" date: 2023-04-24T19:28:40-03:00 tags: ["django", "user", "python"] -draft: false +slug: extending-django-user-profile-model --- The [user authentication](https://docs.djangoproject.com/en/4.2/topics/auth/#user-authentication-in-django) system provided by Django is extremely powerful diff --git a/content/posts/20230501-extending-django-user-with-custom-model.md b/content/posts/20230501-extending-django-user-with-custom-model.md new file mode 100644 index 0000000..72a7752 --- /dev/null +++ b/content/posts/20230501-extending-django-user-with-custom-model.md @@ -0,0 +1,237 @@ +--- +title: "Extending built-in Django User with a custom Model" +date: 2023-05-01T19:28:40-03:00 +tags: ["django", "user", "python"] +slug: extending-django-user-with-custom-model +--- + +The [user authentication](https://docs.djangoproject.com/en/4.2/topics/auth/#user-authentication-in-django) system provided by Django is extremely powerful +and handles most of the authentication (Am I who I say I am?) and authorization (Am I +authorized to do what I want to do?) needs of an web project. User accounts, groups +and permissions, methods for handling passwords securely are part of this system. + +Generally, this is adequate for most projects; however, there are situations where it becomes necessary to modify the behavior of a **User** or alter how their data is stored in the database. It should be noted that modifying the authorization and/or authentication process of a **User** will not be covered in this post. + +Creating a user profile model is one solution to extend and modify the behavior of a **User**, as [discussed before]({{< ref "20230424-extending-django-user-profile-model" >}}), but that approach has some caveats that are solved with the use of a +custom user model. + +# Custom User model + +We can tell Django which is the model that will replace the built-in +`django.contrib.auth.models.User` model in the system. This is done by +providing a value to `AUTH_USER_MODEL` in your project. + +{{}} +# myproject/myproject/settings.py +AUTH_USER_MODEL = "users.CustomUser" +{{}} + +> Usually I create a `users` application to group all custom user related +> code to keep everything in the same context + +It is highly recommended that you do this configuration at the beginning +of the project, as after you have created your database tables, it will +require you to fix your schema, moving data between tables and reapplying +some migrations manually (see [#25313](https://code.djangoproject.com/ticket/25313) +for an overview of the steps involved). + +Now we need to create our custom model. + +This new user model can handle different authentication and authorization +schemes, can use different fields (e.g. email) to identify the user or +any other requirement that is not satisfied using the default Django user +model. + +## Adding new fields to default User model + +If the default **[User](https://docs.djangoproject.com/en/4.2/ref/contrib/auth/#django.contrib.auth.models.User)** model has everything we need and we want +to add some extra profile fields keeping authentication and authorization as +it is, create a custom model inheriting from `AbstractUser` would be enough. + +{{}} +# myproject/users/models.py +from django.contrib.auth.models import AbstractUser + +class CustomUser(AbstractUser): + date_of_birth = models.DateField(null=True) +{{}} + +{{}} +# myproject/myproject/settings.py +AUTH_USER_MODEL = "users.CustomUser" +{{}} + +As we will not create a new table to store the user related information, there is +no need for additional database queries to retrieve related models. We also don't +need to worry if a related model is created or not reducing the complexity of +the system. + +## AbstractBaseUser + +If we want to use a different field as the identifier (other than `email`), +use a different authorization system and/or having more control on what +fields we have in our user model, a custom model inheriting from +`AbstractBaseUser` is the choice. + +`AbstractBaseUser` is the core implementation of a **User**. It has a +`password` field and methods to store and validate it securely. A +`last_login` datetime field and everything else is up to us to provide. + +If using the default authentication backend, our model must have a single unique +field that will be the identifier of our user such as email address, username or +any other unique attribute. + +You configure that attribute using `USERNAME_FIELD` that defines what is +the field that will uniquely identify the user. + + + + + +`EMAIL_FIELD` + +`REQUIRED_FIELDS` + +`is_active` is an attribute on `AbstractBaseUser` defaulting to `True` + +As an example, we will define a custom user that will use the email address +as the identifier, has the date of birth as one required field can store +the phone number and has a flag field in the database to indicate if the user +is active or not. + +{{}} +# myproject/users/models.py +from django.contrib.auth.models import AbstractBaseUser + +class CustomUser(AbstractBaseUser): + USERNAME_FIELD = "email" + EMAIL_FIELD = "email" + REQUIRED_FIELDS = ["date_of_birth", ] + + date_of_birth = models.EmailField(unique=True) + email = models.EmailField(unique=True) + is_active = models.BooleanField(default=True) + phone_number = models.CharField(max_length=16, blank=True) +{{}} + + + +FROM DOCS Authentication backends provide an extensible system for when a username and password stored with the user model need to be authenticated against a different service than Django’s default. + +TODO: list all fields that are created with this + +Any other fields needs to be created. + + is_active is a property set to True, but you can define if you want + +USERNAME_FIELD is needed identifier unique = True +EMAIL_FIELD to specifi what is the email field +REQUIRED_FIELDS fields required when createsuperuser + +If we want to use `email` as the identifier of an user, +we need to set `USERNAME_FIELD` property + +{{}} +# myproject/users/models.py +class CustomUser(AbstractBaseUser): + USERNAME_FIELD = "email" + + email = models.EmailField() +{{}} + +One drawback is you need to specify a Custom Manager implementing +two methods: `create_user` and `create_superuser`. This is required +so we willll be able to run `python manage.py createsuperuser` +and `python manage.py create-user`. + +If some fields (TODO list what fields) from `ABstractUser` are there, you can +use the built-in UserManager +FROM DOCS username, email, is_staff, is_active, is_superuser, last_login, and date_joined fields the same as Django’s default user, you can install Django’s UserManager + +{{}} +# myproject/users/models.py +class CustomUser(AbstractBaseUser): + USERNAME_FILED = "email" + + email = models.EmailField() + + objects = UserManager() +{{}} + +If you don't want to use Django Admin (very unlikely), you're done, +and you can create/manage your users and authentication backend will +be able. + +However, if you want to use this custom user model with Django admin, there are +some extra steps. + +We need some fields and methods: +`is_staff` so you have access to django admin +`is_active` inactive users can't access django admin + +to manage permissions to edit registered models +`has_perm` +`has_module_perms()` +***we don't need to use the built-in permission system (see PermissionMixin)*** + +And `UserCreationForm`< `UserChangeForm` and `PasswordResetForm` (if we don't have email field) +needs to be customized so we can use that. + +Also we need a custom UserAdmin to use our custom forms. + +This is a lot of things, and sometimes difficult to remember. The docs +are ok to describe the process, but IMO this should be much simpler :-P + +If by any chance you want to use django model permission, you can +use PermissionMixin, so you have access to groups, etc (to be honest, I +never saw anything using permission, but groups) + + + + + + + + + + + + + + + + + +Sometimes the username may not be the way you want to identify an user +(an email or social number would be more suitable for your project) +or we have different requirements for authorization and permission. In +those cases creating a custom user model is a option. + +This has advatanges over the user of a user profile model and solve some +of the caveats of that approach such as: + +- We won't need an extra database table to store your custom fields, so + there is no performance problems to access them; +- As the table that we store the User data required for Django authentication + is the same, we don't need to bother if your profile fields will be available + or not + +When creating a custom user model, we have two different options +If you are going to this path, you can create your custom user +inheriting from two different classes: + + + + + + +If using Django Admin, we also need to register this new model. + +{{}} +# myproject/users/admin.py +from django.contrib import admin +from django.contrib.auth.admin import UserAdmin +from .models import CustomUser + +admin.site.register(CustomUser, UserAdmin) +{{}} \ No newline at end of file