<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Sarah Abderemane's Website - django</title><link href="https://sarahabd.com/" rel="alternate"></link><link href="https://sarahabd.com/feeds/rss-django.xml" rel="self"></link><id>https://sarahabd.com/</id><updated>2026-05-06T18:00:00+02:00</updated><entry><title>Me and Mentorship</title><link href="https://sarahabd.com/blog/me-and-mentorship" rel="alternate"></link><published>2026-05-06T18:00:00+02:00</published><updated>2026-05-06T18:00:00+02:00</updated><author><name>Sarah Abderemane</name></author><id>tag:sarahabd.com,2026-05-06:/blog/me-and-mentorship</id><summary type="html">&lt;p class="first last"&gt;Mentoring is a great way to learn, some of my reflexions on mentoring and contributing to open source projects.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Hi there.. it’s been a while as usual… 😄&lt;/p&gt;
&lt;p&gt;Today I would like to talk about mentoring. It’s been a constant in my
life. I have been on both sides: mentee and mentor. I can tell you that
you learn so much from this exchange.&lt;/p&gt;
&lt;p&gt;Being a mentee is a way to learn from an expert or just people who know
more than yourself. Those people you truly admire for their work. The
mentees don’t even always tell how much they admire their mentors.&lt;/p&gt;
&lt;p&gt;On the reverse, being a mentor is a good way to learn how to share your
knowledge the best way. You watch the person you’re mentoring grow and
make their own decisions, without ever having to ask you for advice in
the end, because you’ve given them the tools to find the answers on
their own. One day, perhaps, they’ll take the time to thank you, because
without even realizing it, you’ve changed their life.&lt;/p&gt;
&lt;p&gt;It’s crazy, isn’t it? I love mentoring because it’s a special and unique
exchange: you feel close to the other person, because when you’re a
mentor, you see a younger version of yourself in your mentee, and the
mentee sees you as what they might one day become. I’m sure many people
don’t see mentoring exactly the way I do, but it’s an extremely
rewarding experience.&lt;/p&gt;
&lt;p&gt;Mentoring is a great way to learn, whether you’re the mentee or the
mentor. Yes, mentors learn from the experience as well. How can you make
sure your mentee has understood what you meant? How can you clearly
explain something that seems obvious to you to the person sitting across
from you? The mentee’s questions help us discover aspects we had never
considered before. There is so much to learn!&lt;/p&gt;
&lt;div class="section" id="google-summer-of-code-mentorship"&gt;
&lt;h2&gt;Google Summer of Code mentorship&lt;/h2&gt;
&lt;p&gt;Speaking about mentoring, I’m going to get my hands dirty again and
mentor someone for Google Summer of Code (GSoC) for the Django
organization this year! 🥳&lt;/p&gt;
&lt;p&gt;It will be my first time to mentor for Google Summer of Code, I’m really
excited! I will be mentoring &lt;a class="reference external" href="https://www.linkedin.com/in/keha-chandrakar-342a1a285/"&gt;Keha
Chandrakar&lt;/a&gt;
with my amazing co-mentor and co-chair of the Website Working Group
&lt;a class="reference external" href="https://saptaks.website/"&gt;Saptak Sengupta&lt;/a&gt;✨&lt;/p&gt;
&lt;p&gt;The project is &lt;a class="reference external" href="https://summerofcode.withgoogle.com/programs/2026/projects/zCsh2gn8"&gt;Unified Dark Mode and UI Consistency for Django’s Issue
Tracker&lt;/a&gt;,
it would be a nice addition for the community.&lt;/p&gt;
&lt;p&gt;This project means a lot to me. I have previously contributed to the
addition of the dark mode in the Django website. It was my first major
contribution to Django! When you start your contribution journey for a
huge project like Django, it’s exciting and impressive! I did contribute
without any mentor but I definitely had help along the way since the
Django community is so welcoming and helpful. I learned a lot through
this contribution and now it’s used by so many people. Being Keha’s
mentor is a good way for me to give back and help someone else on a
topic I know pretty well!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="you-could-be-the-mentor"&gt;
&lt;h2&gt;You could be the mentor&lt;/h2&gt;
&lt;p&gt;I have been part of the &lt;a class="reference external" href="https://djangonaut.space"&gt;Djangonaut Space&lt;/a&gt;
organization, where we are recruiting people as mentors.
This organization and the Django organization are always looking for mentors.
If you have already contributed to an open source project related to the
Django ecosystem or are maintaining one and you are willing to take the
time to help someone in their contribution journey, consider mentoring
as an option to get new contributors to your project. Djangonaut Space
has multiple cohorts, &lt;a class="reference external" href="https://buttondown.com/djangonaut-space"&gt;sign up to the newsletter and mention your
interest in mentoring&lt;/a&gt;:
being a navigator (technical mentor) or a captain (community mentor).&lt;/p&gt;
&lt;p&gt;Who knows, this might be your new co-maintainer, your new teammate or
your new code reviewer? There are things we can definitely learn on our
own and some things you will only learn from someone else.&lt;/p&gt;
&lt;p&gt;That’s it for me!&lt;/p&gt;
&lt;/div&gt;
</content><category term="blog"></category><category term="reflexion"></category><category term="django"></category></entry><entry><title>DjangoCon Africa 2025</title><link href="https://sarahabd.com/blog/djangocon-africa-2025" rel="alternate"></link><published>2025-08-28T04:00:00+02:00</published><updated>2025-08-28T04:00:00+02:00</updated><author><name>Sarah Abderemane</name></author><id>tag:sarahabd.com,2025-08-28:/blog/djangocon-africa-2025</id><summary type="html">&lt;p class="first last"&gt;Hi there, it’s have been a while… I have been for the first time to DjangoCon Africa few weeks ago. It was in Arusha, Tanzania.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Hi there, it's been a while as usual. I have been for the first time to DjangoCon Africa few weeks ago. It was in Arusha, Tanzania.&lt;/p&gt;
&lt;p&gt;Tim Schilling has written an excellent blog post about his experience at DjangoCon Africa, you can read &lt;a class="reference external" href="https://www.better-simple.com/django/2025/08/25/djangocon-africa-2025-recap/"&gt;his blog post&lt;/a&gt;.
He collected the other abstracts from the conference participants.&lt;/p&gt;
&lt;div class="section" id="first-djangocon-africa"&gt;
&lt;h2&gt;First DjangoCon Africa&lt;/h2&gt;
&lt;p&gt;It's always a special feeling when it's your first time in a conference.
You meet new people, discover how the conference is run and familiarize yourself with the organization and how it is supposed to work.&lt;/p&gt;
&lt;p&gt;I know DjangoCon Europe well, I have been an organizer, a volunteer and an attendee.
One thing you have to know is DjangoCon events are run by volunteers for free.
I really would like to thank the organizers and volunteers behind this conference.
I know it's a lot of work behind the scenes, but gathering people in one place and seeing folks connecting and share knowledge it's a priceless joy.
If you want to help the community globally, this is a really good way to contribute.&lt;/p&gt;
&lt;p&gt;Moreover, I would like to thank all the sponsors that made this conference possible.
This is particularly important to me because the community must be represented as a whole across all continents and conference like this one is the best way to show that.&lt;/p&gt;
&lt;div class="figure"&gt;
&lt;img alt="Thibaud Colas and I in front the wall of DjangoCon Africa UbuCon Africa with all sponsors logos. We are showing the name of the conference and both smiling." src="../images/me-thibaud-wall.jpg" /&gt;
&lt;p class="caption"&gt;Thibaud and I showing the DjangoCon Africa UbuCon Africa wall&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;I am proud of this picture, Me and Thibaud Colas, Vice President and President, in front the wall of DjangoCon Africa UbuCon Africa with all sponsors logos.
Sponsoring is crucial for the success of such events and if you care about diversity and inclusion in tech, supporting events like DjangoCon Africa is a great way to make a difference.&lt;/p&gt;
&lt;p&gt;As a board member, I am glad to have been able to participate in almost all Django events organized around the world so far to be in direct contact with the community.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="arusha-tanzania"&gt;
&lt;h2&gt;Arusha, Tanzania&lt;/h2&gt;
&lt;p&gt;I have never been to South of Africa except the country I have roots, &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Comoro_Islands"&gt;Comoros Islands&lt;/a&gt;.
Go to DjangoCon Africa was a good way to discover that and learn about Tanzania.
I really enjoyed Arusha, it's a lovely city. It was a real change of landscape for me, coming from Paris.&lt;/p&gt;
&lt;div class="figure"&gt;
&lt;img alt="Road with closed shops in multi-colored jails in Arusha, Tanzania" src="../images/road-with-shops.jpg" /&gt;
&lt;p class="caption"&gt;Road with shops in Arusha, Tanzania&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;It's also a good opportunity to discover the local culture, food and wildlife.
I had the time to do a Safari to Ngorongoro Crater with my lovely friend &lt;a class="reference external" href="https://www.better-simple.com/"&gt;Tim Schilling&lt;/a&gt;, go to the markets and try the local food.&lt;/p&gt;
&lt;div class="figure"&gt;
&lt;img alt="Tim Shilling and I in the Jeep during the safari" src="../images/safari-with-tim.jpg" /&gt;
&lt;p class="caption"&gt;Safari with Tim Schilling&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Also, you see the challenge people are facing there and doing their best to overcome them. Despite this, people are welcoming and friendly. Always trying to help.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-conference"&gt;
&lt;h2&gt;The conference&lt;/h2&gt;
&lt;p&gt;Since it's a new conference for me, I tried my best to talk with as many folks as possible.
I was amazed by all the folks that came to me to talk, just for chatting or thanks me for my keynote and/or get feedback for their projects.
Usually it's the reverse, I will go to folks to talk to them. If you were at DjangoCon Africa and didn't connect with me, you can still do it!&lt;/p&gt;
&lt;p&gt;Outside of the local community, this conference gave me the opportunity to met old friends and new friends.
Conferences are a great way to see your international friends and meet new folks from everywhere.
I know folks from all over the world, that's really cool no? 😁&lt;/p&gt;
&lt;div class="figure"&gt;
&lt;img alt="Group photo of everyone in DjangoCon Africa 2025" src="../images/group-photo.jpg" /&gt;
&lt;p class="caption"&gt;Everyone in front the wall before the end of the conference&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Something I love is to meet folks from &lt;a class="reference external" href="https://djangonaut.space/"&gt;Djangonaut Space&lt;/a&gt; in person in addition to the local community.
I was able to meet &lt;a class="reference external" href="https://www.linkedin.com/in/salim-abdella/"&gt;Salim Nuru&lt;/a&gt;, &lt;a class="reference external" href="https://www.philipnarteh.me/"&gt;Philip Nareth&lt;/a&gt; and Tim Schilling in person.&lt;/p&gt;
&lt;div class="figure"&gt;
&lt;img alt="Five members of Djangonaut Space meeting up at DjangoCon Africa 2025, smiling and pointing to the sky!" src="../images/djcafrica-djangonauts.jpg" /&gt;
&lt;p class="caption"&gt;The Djangonaut Space crew at DjangoCon Africa 2025&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;I'm sad &lt;a class="reference external" href="https://rahma.hashnode.dev/"&gt;Rahmat Akintola&lt;/a&gt; wasn't able to come, next time hopefully.&lt;/p&gt;
&lt;p&gt;Now I can say I have seen all the founders and co-founders of Djangonaut Space in person 🚀&lt;/p&gt;
&lt;p&gt;Tim is one of my very good friends, I was so happy to meet him in person and be able to support him for his keynote.
It's unbelievable that was the first time we met in person, after all the time we spent together on Djangonaut Space.
Remote relationships are real.&lt;/p&gt;
&lt;p&gt;I was glad to finally see folks who I have chatted with online occasionally like &lt;a class="reference external" href="https://www.linkedin.com/in/juliusboakye/"&gt;Julius Boakye&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="opening-keynote"&gt;
&lt;h2&gt;Opening Keynote&lt;/h2&gt;
&lt;p&gt;I was deeply honored to give the opening keynote of DjangoCon Africa: &amp;quot;50 shades of green - One contribution to the Django world&amp;quot;.
For those who are interested, you have the &lt;a class="reference external" href="https://sarahabd.com/shades"&gt;link of the slides&lt;/a&gt; . I will see to add the transcript later.&lt;/p&gt;
&lt;div class="figure"&gt;
&lt;img alt="Me giving the opening keynote at DjangoCon Africa 2025" src="../images/me-keynoting.jpg" /&gt;
&lt;/div&gt;
&lt;p&gt;If my keynote has any impact on you, even years later, please tell me, I would like to hear your story!&lt;/p&gt;
&lt;p&gt;Unfortunately, talks were not recorded at this conference. I hope it will be the case next time, some content deserves to be shared beyond Africa.&lt;/p&gt;
&lt;p&gt;Each interaction has left a mark on my journey, and I look forward to continuing these conversations in the future.
I got some contacts for potential collaborations and projects, and I'm excited to see where these connections and projects will lead.&lt;/p&gt;
&lt;p&gt;As I mentioned in my keynote, I would like to encourage folks to contribute to Django and open source in general.
There are many ways to contribute, whether it's through code, documentation, internationalization or community support. Every little bit helps!
And even if it feels scary to start contributing, remember that everyone was a beginner at some point. Myself included.&lt;/p&gt;
&lt;p&gt;So don't be afraid to take that first step and get involved. The Django community is a friendly and welcoming place.&lt;/p&gt;
&lt;hr class="docutils" /&gt;
&lt;p&gt;This trip was especially meaningful for me. Despite navigating some personal challenges, the warmth and generosity of the community helped me set those worries aside.
My time at DjangoCon Africa was truly enriching, and I look forward to the possibility of returning in 2027.&lt;/p&gt;
&lt;p&gt;See you next time DjangoCon Africa! 💚&lt;/p&gt;
&lt;/div&gt;
</content><category term="blog"></category><category term="reflexion"></category><category term="django"></category><category term="conferences"></category></entry><entry><title>DSF Vice President 2025</title><link href="https://sarahabd.com/blog/dsf-vice-president-2025" rel="alternate"></link><published>2025-02-20T12:00:00+01:00</published><updated>2025-02-20T12:00:00+01:00</updated><author><name>Sarah Abderemane</name></author><id>tag:sarahabd.com,2025-02-20:/blog/dsf-vice-president-2025</id><summary type="html">&lt;p class="first last"&gt;Hi there, it has been a while since my last post, but I'm now back with a new role...&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Hi there, it's been a while, as always 🙂
I had a though end of the 2024 year and beginning of 2025 (family loss) so I didn't do my usual year in review unfortunately, but I took the time to write my recent update: I'm the new Vice President of the Django Software Foundation 🎉&lt;/p&gt;
&lt;p&gt;This is such an honor to serve on the board of the Django Software Foundation, and it's even more the case as the Vice President. I'm particularly glad to have this role since it's a way to connect to our members and I already had lovely emails responses while onboarding new DSF members.&lt;/p&gt;
&lt;div class="section" id="vice-president-tasks"&gt;
&lt;h2&gt;Vice President tasks&lt;/h2&gt;
&lt;p&gt;The Vice President handle everything related to requests of new DSF members. Currently you can apply for yourself or apply for someone else. After that, it's reviewed and voted by the board for approval or not.&lt;/p&gt;
&lt;p&gt;If you planning to submit a DSF member, please add as many informations as you can, it's really helping us to know if the person meet the criterias to approuve the member.&lt;/p&gt;
&lt;p&gt;My tasks are:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;send emails to approved members&lt;/li&gt;
&lt;li&gt;add them to the mailing list used for the voting for the future boards and steering council&lt;/li&gt;
&lt;li&gt;add them to the private DSF member section in the forum&lt;/li&gt;
&lt;li&gt;attribute them the DSF role&lt;/li&gt;
&lt;li&gt;follow up for any specific inquiries related to current or onboarding members&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Besides that, I'm also the fallback of the President. If Thibaud is sick or can't do something related to his role, I will be the one to fill up the place. No fear, right? 😛&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="https://thib.me/president-of-the-django-software-foundation"&gt;As Thibaud was saying in his blog&lt;/a&gt;, there is some discovery to do to be able to fill the role as people and ourselves expected. I'm sure we will figure it out and document it 💪🏽
The President seems to be a role with many things to do and I will do my best to help him as much as I can.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="my-plans-for-2025-and-the-future"&gt;
&lt;h2&gt;My plans for 2025 and the future&lt;/h2&gt;
&lt;p&gt;I have been doing a lot of volunteering last year, one thing which is hard, is get a good balance to be able to do everything you wanted and take time for yourself. In function of your personality, it can be even harder to say no to a topic you care about just because you don't have enough time. That's why, my first plan is to improve processes and document things internally for the Vice President in case I decide to not continue to serve the board.&lt;/p&gt;
&lt;p&gt;This year I would like to automate partially or completely the process of onboarding a new DSF member to have less time gap in terms of announcement of members approval and the time they are actually onboarded and added. This will be also a way to allow the Vice President to spend time on other things too.&lt;/p&gt;
&lt;p&gt;I will continue my work related what I mentioned in my statement and will do my best to represent the Django Software Foundation and this nice framework and people behind it around the world 💚&lt;/p&gt;
&lt;p&gt;I will see to achieve things I haven't done as many actions as I wanted (Accessibility, Django website etc.) and support other board members and any folks who are happy to step in, in the Django governance and Django work that fulfill the DSF's mission.&lt;/p&gt;
&lt;/div&gt;
</content><category term="blog"></category><category term="django"></category><category term="dsf"></category><category term="reflexion"></category></entry><entry><title>DSF Board, AMA after 8 months</title><link href="https://sarahabd.com/blog/dsf-board-ama-after-8-months" rel="alternate"></link><published>2024-11-16T06:00:00+01:00</published><updated>2024-11-16T06:00:00+01:00</updated><author><name>Sarah Abderemane</name></author><id>tag:sarahabd.com,2024-11-16:/blog/dsf-board-ama-after-8-months</id><summary type="html">&lt;p class="first last"&gt;My experience and all the questions folks have asked me about DSF Board&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Hi there, it's been a while, I always have many ideas to write and no time,
but I try to find some to talk about the &lt;a class="reference external" href="https://www.djangoproject.com/foundation/"&gt;Django Software Foundation&lt;/a&gt; (DSF) board.
I might forget things to say so I might do a DSF blog series.
This time I decided to re-write this post and directly answer questions I was asked on social media or in person.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DISCLAIMER&lt;/strong&gt;: This is my personal opinion, I do not intend to blame anyone except myself.
This is my reflection from the past few months, including the fact I’m still learning about the board.&lt;/p&gt;
&lt;div class="section" id="how-did-you-become-a-dsf-board-member"&gt;
&lt;h2&gt;How did you become a DSF board member?&lt;/h2&gt;
&lt;p&gt;I was elected by &lt;a class="reference external" href="https://www.djangoproject.com/foundation/individual-members/"&gt;DSF members&lt;/a&gt;. If you want to learn more about DSF membership,
you can check the django website and if you think you or someone else are suitable, please apply.
I started to serve on the board from January 2024, and my term will end in December 2025.
Each board member have 2 term year and we have 4 specific officer roles:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;President&lt;/li&gt;
&lt;li&gt;Vice President&lt;/li&gt;
&lt;li&gt;Treasurer&lt;/li&gt;
&lt;li&gt;Secretary&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I don’t have any specific role, I was planning to see how it’s going and then see what I can do.
And also, how it will go with my current tasks and (huge) to-do list.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="whats-different-from-your-expectations"&gt;
&lt;h2&gt;What’s different from your expectations?&lt;/h2&gt;
&lt;p&gt;I think coming back from &lt;a class="reference external" href="https://djangonaut.space/"&gt;Djangonaut Space&lt;/a&gt; organization I was expecting some similarities in terms of communication
and organisation but it wasn't the case. I was expecting more asynchronous communication and interaction since
we might all be busy for many reasons.&lt;/p&gt;
&lt;p&gt;A bit more defined things like who should answer emails and what about spams for example.&lt;/p&gt;
&lt;p&gt;1h of board meetings a month is not enough to me and some topics are not really discussed outside the meetings.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="what-do-you-think-needs-to-happen-in-the-future-to-set-the-board-and-the-dsf-up-for-long-term-success"&gt;
&lt;h2&gt;What do you think needs to happen in the future to set the board and the DSF up for long term success?&lt;/h2&gt;
&lt;p&gt;Put more effort in fundraising, I believe having more money will help to take actions in more domains.&lt;/p&gt;
&lt;p&gt;Also, have a better link with the community.
Sometimes we have issues where having feedback and support from the community would be helpful to address them.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="how-many-of-your-dsf-board-specific-initiatives-are-things-that-could-be-done-not-being-a-board-member"&gt;
&lt;h2&gt;How many of your DSF board specific initiatives are things that could be done NOT being a board member?&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;For example, solving the problem of onboarding and nurturing new contributors is tackled by Djangonaut Space
on our own initiative. But approving grants and selecting a DjangoCon Europe team can only be done by board members.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So many things can be done without being a board member actually 😁&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Help people in the &lt;a class="reference external" href="https://forum.djangoproject.com/"&gt;Django forum&lt;/a&gt; or &lt;a class="reference external" href="https://discord.gg/xcRH6mN4fa"&gt;Django discord&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Moderate the forum and discord&lt;/li&gt;
&lt;li&gt;Initiate a &lt;a class="reference external" href="https://github.com/django/dsf-working-groups"&gt;working group&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Participate to a working group&lt;/li&gt;
&lt;li&gt;Help with the content of the Django’s website&lt;/li&gt;
&lt;li&gt;Submit people as DSF members&lt;/li&gt;
&lt;li&gt;Create a local Django community (ie: Django Paris meetup)&lt;/li&gt;
&lt;li&gt;Search for community around the world to add to &lt;a class="reference external" href="https://www.djangoproject.com/community/local/"&gt;the local community page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Contribute to djangoproject.com / code.djangoproject.com website&lt;/li&gt;
&lt;li&gt;Contribute to the &lt;a class="reference external" href="https://github.com/django-discord/bot"&gt;Django Discord bot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Contribute to Django core to improve processes&lt;/li&gt;
&lt;li&gt;Contribute to a &lt;a class="reference external" href="https://www.djangoproject.com/foundation/teams/"&gt;Django team&lt;/a&gt; (ie: Triage and review team)&lt;/li&gt;
&lt;li&gt;Talk to people who could be part of a working group&lt;/li&gt;
&lt;li&gt;Volunteer in Django/DSF presence in events (ie: help run a Django booth)&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="small-ways-to-get-involved-if-i-only-have-5-hours-per-month-i-can-contribute-where-do-you-need-people"&gt;
&lt;h2&gt;Small ways to get involved: If I only have 5 hours per month I can contribute, where do you need people?&lt;/h2&gt;
&lt;p&gt;They are many ways to contribute depends on the things you are more interested:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Immediate actions&lt;/strong&gt;&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Help social media WG to provide content or review content&lt;/li&gt;
&lt;li&gt;Help Djangonauts on the forum or on discord, answer questions&lt;/li&gt;
&lt;li&gt;Retweet/retooth Django posts&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Might need review / futures actions&lt;/strong&gt;&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Help on moderation (for example Reddit /r/django)&lt;/li&gt;
&lt;li&gt;DSF Fundraising WG might need extra help to reach potential sponsors&lt;/li&gt;
&lt;li&gt;If possible, come on the &lt;a class="reference external" href="https://www.djangoproject.com/weblog/2024/oct/16/announcing-weekly-dsf-office-hours/"&gt;DSF office hours&lt;/a&gt; to help answers or contribute to the conversation&lt;/li&gt;
&lt;li&gt;I would like at some point to have a content team for the website and help would be helpful here&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are interested in any of those actions please fill &lt;a class="reference external" href="https://framaforms.org/help-sarah-in-her-dsf-mission-1731706938"&gt;this form&lt;/a&gt;,
so I can reach you later if there are any specific needs.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="if-and-how-the-dsf-is-setting-and-tracking-goals-for-diversity-and-inclusion"&gt;
&lt;h2&gt;If and how the DSF is setting and tracking goals for diversity and inclusion?&lt;/h2&gt;
&lt;p&gt;We have a &lt;a class="reference external" href="https://www.djangoproject.com/diversity/"&gt;public statement for diversity&lt;/a&gt; and some ongoing DEI improvements.&lt;/p&gt;
&lt;p&gt;Currently it’s more to define what is the existing state and the evolution with statistics to be able to set goals.&lt;/p&gt;
&lt;p&gt;The actions that had been taken is mostly to show how diverse the community is in the Django world, which means:
the website, elections, the members and Django communication tools:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;The local community page&lt;/li&gt;
&lt;li&gt;Recognize DSF members from all over the world&lt;/li&gt;
&lt;li&gt;Small initiatives to help to get a good representation of the diversity of the community in DSF board elections&lt;/li&gt;
&lt;li&gt;Talk about the current DSF members&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Could be even more, having Django participate in the &lt;a class="reference external" href="https://www.outreachy.org/"&gt;Outreachy program&lt;/a&gt; and so on.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="what-are-the-tasks-and-time-commitments"&gt;
&lt;h2&gt;What are the tasks and time commitments?&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Regular tasks as a baseline and then ad-hoc tasks/personal initiatives with rough times&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We have a meeting each month and it lasts one hour. During this time, we are reviewing all current and new business
with all members and the assistant Catherine.&lt;/p&gt;
&lt;p&gt;Except that, we have async communication on slack.&lt;/p&gt;
&lt;p&gt;Since I don't have a specific role, it's mostly promotion and representation of the Django Software Foundation and
following DSF working groups as a board of liaison. We have a contact form so I have to check emails and reply if
I can.&lt;/p&gt;
&lt;p&gt;In more ad-hoc tasks/personal initiatives, I don’t know precisely the time but I think it depends on the task,
if it’s research on a topic or doing something for a working group. I’m involved in 3 working groups,
which means that there might be meetings or actions that I may have to do related to that.&lt;/p&gt;
&lt;p&gt;It’s hard to explicitly define times, but I think I could say around 5+ hours a month, depending on the need and
my health.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="what-areas-do-you-think-the-board-could-improve-on-and-where-does-it-lack-skills-expertise"&gt;
&lt;h2&gt;What areas do you think the board could improve on and where does it lack skills/expertise?&lt;/h2&gt;
&lt;p&gt;I think the board could improve in promotion: get sponsors, offer sponsorship package in function of the level
of sponsoring, get contacts…&lt;/p&gt;
&lt;p&gt;And I believe in terms of legal considerations and marketing we are lacking expertise.
For example Django is known from developers for its stability and smooth upgrades, this is something
which is not promoted, or at least poorly by saying it’s “boring”.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="any-behind-the-curtain-stuff-any-pain-points"&gt;
&lt;h2&gt;Any &amp;quot;behind the curtain&amp;quot; stuff? Any pain points?&lt;/h2&gt;
&lt;p&gt;Should I really share behind the curtain stuff? 😁&lt;/p&gt;
&lt;p&gt;I think the major pain point for me was communication and documentation.&lt;/p&gt;
&lt;p&gt;Many things are not documented or partially and with all different boards I imagine things have been lost over time.
It’s hard to understand everything when you are new.&lt;/p&gt;
&lt;p&gt;Also, I would have preferred to have the tasks shared or potentially allow/push people to ask for help if no time
or whatever reason, especially when they have a role which can ask a lot.
It took me a lot of time to figure out who writes our news pages.
Access and the processes to ask for access are not always clear to me.
This kind of thing should be documented somewhere.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="how-does-the-board-decide-things-do-you-vote-on-everything"&gt;
&lt;h2&gt;How does the board decide things (do you vote on everything)?&lt;/h2&gt;
&lt;p&gt;As I was saying before, we have a board meeting each month and we have a precise agenda that we are reviewing
together:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Grant submissions&lt;/li&gt;
&lt;li&gt;DjangoCon proposal&lt;/li&gt;
&lt;li&gt;DSF memberships&lt;/li&gt;
&lt;li&gt;DSF working group&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of those areas are voted on each time if there is anything to vote on,
so we are making sure that we have a quorum before the start of the meeting, otherwise it will be rescheduled.
We also discuss things related to the DSF organisation like bylaws, trademark etc.
but things aren’t always under vote except if there is a major change.
All board members can add a topic to the agenda.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="what-things-folks-should-involve-the-board-with-and-what-can-they-just-do"&gt;
&lt;h2&gt;What things folks should involve the board with and what can they &amp;quot;just do&amp;quot;.&lt;/h2&gt;
&lt;p&gt;Some &lt;a class="reference external" href="https://github.com/django/dsf-working-groups"&gt;DSF working groups&lt;/a&gt; already exist, all members are identifiable and the way to join the working group.&lt;/p&gt;
&lt;p&gt;Everyone can help a working group without asking a board member.&lt;/p&gt;
&lt;p&gt;Everyone can create a DSF working group, but this needs at least one board member to follow and guide the
working group (=board liaison) with the DSF board vision and for reporting. When the proposal is ready,
the board liaison will bring it to the board meeting to be voted on by the board.&lt;/p&gt;
&lt;p&gt;There are also initiatives like Djangonaut Space, &lt;a class="reference external" href="https://django-news.com/"&gt;Django News&lt;/a&gt; etc. which don’t rely on the board at all,
if you have an idea which might solve something in the Django community, please do it!&lt;/p&gt;
&lt;p&gt;The major thing which involves the board is creating a new DjangoCon since the name is registered under
the Django trademark with certain criterias. You can still create smaller events without the board,
and some of them are registered in &lt;a class="reference external" href="https://www.djangoproject.com/community/local/"&gt;the local community page&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="your-personal-reflections-is-this-a-joy-or-a-chore"&gt;
&lt;h2&gt;Your personal reflections - is this a joy or a chore?&lt;/h2&gt;
&lt;p&gt;Hard to say, I have experienced both.&lt;/p&gt;
&lt;p&gt;I was frustrated to not be able to help in some cases or see people complaining but I didn’t get the information
at the board level directly where it could make a difference. So I keep notes and try to make changes but sometimes
it’s even just a matter of time or actions, it doesn’t go like you wanted and you’re disappointed with the result.&lt;/p&gt;
&lt;p&gt;I also enjoy people thanking me for some actions I have done, see them amazed with the DSF membership recognition
or just see people I know from other spaces (Djangonaut Space, Discord…) taking part in Django community contributions
in some way, even if it doesn’t end as expected like elections, this is really nice to see all folks from all over the
world gather for one thing in common.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="where-are-you-at-with-your-goals-are-we-on-track-if-we-aren-t-what-resources-would-it-take-to-accomplish-them"&gt;
&lt;h2&gt;Where are you at with your goals? Are we on track? If we aren't, what resources would it take to accomplish them.&lt;/h2&gt;
&lt;p&gt;If we retake &lt;a class="reference external" href="https://www.djangoproject.com/weblog/2023/nov/13/2024-dsf-board-candidates/"&gt;my personal statement from the Django blog post&lt;/a&gt;,
this is the current state:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;span class="underline"&gt;Increase fundraising&lt;/span&gt;: &lt;strong&gt;in progress&lt;/strong&gt; with DSF Fundraising WG
        &lt;ul&gt;
            &lt;li&gt;&lt;span class="underline"&gt;improving communication&lt;/span&gt;: ideas was shared with DSF social media WG, missing coordination with DSF Fundraising WG when the team have everything ready for&lt;/li&gt;
            &lt;li&gt;&lt;span class="underline"&gt;highlighting sponsors&lt;/span&gt;: this will be reviewed with the future DSF Website WG with coordination of DSF Fundraising WG&lt;/li&gt;
        &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;span class="underline"&gt;Develop our community&lt;/span&gt;:  &lt;strong&gt;in progress&lt;/strong&gt; with many new DSF members and newcomers
        &lt;ul&gt;
            &lt;li&gt;&lt;span class="underline"&gt;specifically helping existing and new contributor&lt;/span&gt;: sharing the community and meeting people in other events.&lt;/li&gt;
        &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;span class="underline"&gt;Working group for mentorship&lt;/span&gt;: &lt;strong&gt;Discussion initiated&lt;/strong&gt;, I’m involved in too many working groups, I have now a volunteer to lead this project ✨ She will need people and resources to help her, an issue will be open soon, keep an eye on that.&lt;/li&gt;
    &lt;li&gt;&lt;span class="underline"&gt;Push accessibility in the framework&lt;/span&gt;: &lt;strong&gt;in progress&lt;/strong&gt;, we have new members and many ideas and discussions on going. This also rely a lot on DSF Website WG which will be soon kickstarted.&lt;/li&gt;
    &lt;li&gt;&lt;span class="underline"&gt;Django's diversity and expand the community&lt;/span&gt;: &lt;strong&gt;in progress&lt;/strong&gt;, have a better representation in Django like candidate elections or people shown in the website.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;I believe we are on track but I can’t do that alone, especially for social media, we will need people to help us to promote and write content.&lt;/p&gt;
&lt;p&gt;There are also topics I would like to have more people involved in:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;DSF Code of Conduct WG&lt;/li&gt;
&lt;li&gt;Moderation of Discord and Forum&lt;/li&gt;
&lt;li&gt;Future team to write content of the website&lt;/li&gt;
&lt;li&gt;Get folks feedbacks in order to make improvements&lt;/li&gt;
&lt;li&gt;Get sponsors feedbacks&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="what-did-you-achieve"&gt;
&lt;h2&gt;What did you achieve?&lt;/h2&gt;
&lt;p&gt;I’m happy with what I have achieved, even though I was thinking I would have done more.&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Represent DSF at some events (e.g. FOSDEM)&lt;/li&gt;
&lt;li&gt;Django booth at EuroPython&lt;/li&gt;
&lt;li&gt;DjangoCon Europe lightning talk&lt;/li&gt;
&lt;li&gt;DjangoCon Europe DSF panel&lt;/li&gt;
&lt;li&gt;Handle DSF roles on discord server&lt;/li&gt;
&lt;li&gt;Reply to some questions on discord, forum or email&lt;/li&gt;
&lt;li&gt;Help to quickstart the DSF Fundraising WG&lt;/li&gt;
&lt;li&gt;Add local communities in local communities page&lt;/li&gt;
&lt;li&gt;Follow-up on draft of the DSF Website WG&lt;/li&gt;
&lt;li&gt;Help on the review of DjangoCon proposal of next year&lt;/li&gt;
&lt;li&gt;Help the social media WG&lt;/li&gt;
&lt;li&gt;Research on the DSF past board and history&lt;/li&gt;
&lt;li&gt;Help on the next Django developer survey&lt;/li&gt;
&lt;li&gt;Submit many people for DSF membership&lt;/li&gt;
&lt;li&gt;Listing of potential requests that Djangonauts would like&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="what-would-you-like-to-achieve"&gt;
&lt;h2&gt;What would you like to achieve?&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Automate partially or completely the addition of new DSF Individual Members&lt;/li&gt;
&lt;li&gt;Improve fundraising to be able to take more actions&lt;/li&gt;
&lt;li&gt;Improve the website with the DSF Website WG&lt;/li&gt;
&lt;li&gt;Create a content website (WG?) team&lt;/li&gt;
&lt;li&gt;Create a mentorship / leadership WG&lt;/li&gt;
&lt;li&gt;Create a way to get feedback from the community&lt;/li&gt;
&lt;li&gt;Improve forms for futures elections&lt;/li&gt;
&lt;li&gt;Create a DSF members blog series&lt;/li&gt;
&lt;li&gt;Create some “did you know” social media post related to DSF&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="what-do-you-wish-the-community-knew-that-would-make-your-role-easier"&gt;
&lt;h2&gt;What do you wish the community knew that would make your role easier?&lt;/h2&gt;
&lt;p&gt;This is actually some time commitment if you want to do things outside of the monthly meeting.
Your work and extra activities take time and some days this is hard to work on open source.&lt;/p&gt;
&lt;p&gt;We need to increase funding but the best way to start is with you, dear lovely reader.
If you are working for a company, you should ask if they are sponsoring Django if they use it and tell them why they should do that.
If you don’t know what to tell for why, you can start by the fact it will help pay our Fellows,
the 2 incredible women who are maintaining the tool every day they are relying on and keep the security and improvements on it.&lt;/p&gt;
&lt;p&gt;Many things could be solved by having money, but not only. Sometimes what we are missing is people.
Having mentors, having people to answer questions, people who moderate platforms, people who contribute to code source.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="what-made-you-laugh"&gt;
&lt;h2&gt;What made you laugh?&lt;/h2&gt;
&lt;p&gt;My onboarding, it was definitely not what I expected, even if I didn’t expect so much to be honest.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="would-you-do-it-again"&gt;
&lt;h2&gt;Would you do it again?&lt;/h2&gt;
&lt;p&gt;I think yes, not because this is particularly fun, but more because some things can change only at some level,
and I think I can be helpful here.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="if-you-had-impostor-syndrome-how-do-you-deal-with-it"&gt;
&lt;h2&gt;If you had impostor syndrome, how do you deal with it?&lt;/h2&gt;
&lt;p&gt;Impostor syndrome is, unfortunately, my best friend, always there I don’t know why lol&lt;/p&gt;
&lt;p&gt;I think it's a question of thinking about the best way, even if I'm not the most competent person,
I think I have something to contribute, and that's why I was elected.&lt;/p&gt;
&lt;/div&gt;
</content><category term="blog"></category><category term="dsf"></category><category term="django"></category></entry><entry><title>TIL: Django constraints</title><link href="https://sarahabd.com/til/django-constraints" rel="alternate"></link><published>2023-08-12T10:00:00+02:00</published><updated>2023-08-12T10:00:00+02:00</updated><author><name>Sarah Abderemane</name></author><id>tag:sarahabd.com,2023-08-12:/til/django-constraints</id><summary type="html">&lt;p class="first last"&gt;I have done some work with constraints recently and I wanted to write something on it just to remind myself.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Hi there,&lt;/p&gt;
&lt;p&gt;I have done some work with constraint recently and I wanted to write
something on it just to remind myself. I hope it’s useful to you too.&lt;/p&gt;
&lt;p&gt;Database constraints are really useful to make sure each row is valid
before to save it. You have two type of constraints you can use just
before to record a new line in a table in Django: &lt;tt class="docutils literal"&gt;CheckConstraint&lt;/tt&gt;
and &lt;tt class="docutils literal"&gt;UniqueConstraint&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;I use PostgreSQL which has powerful tools, you can set database
constraint according what is implemented by Django.&lt;/p&gt;
&lt;p&gt;Explanations are always better with an example so here is a constraint
to avoid date overlapping between the start date and the end date:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;   &lt;span class="n"&gt;start_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DateField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;   &lt;span class="n"&gt;end_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DateField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;   &lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="n"&gt;constraints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;         &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CheckConstraint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;               &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start_at__lt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;end_at&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;               &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'start_at_before_end_at'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;         &lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;         &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UniqueConstraint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;               &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'start_date'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'end_date'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;               &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'unique_event_dates'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;         &lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;CheckConstraint&lt;/tt&gt; ensures that the &lt;tt class="docutils literal"&gt;start_at&lt;/tt&gt; is before the
&lt;tt class="docutils literal"&gt;end_at&lt;/tt&gt;. The &lt;tt class="docutils literal"&gt;UniqueConstraint&lt;/tt&gt; ensures that there are no two
events with the same &lt;tt class="docutils literal"&gt;start_date&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;end_date&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;I discovered that if you want to make a &lt;tt class="docutils literal"&gt;UniqueConstraint&lt;/tt&gt; in Django,
it considers &lt;tt class="docutils literal"&gt;NULL&lt;/tt&gt; values as distinct, which I didn’t want in my
case.&lt;/p&gt;
&lt;p&gt;Going back to my previous example, here we have 2 records:&lt;/p&gt;
&lt;table border="1" class="docutils"&gt;
&lt;colgroup&gt;
&lt;col width="9%" /&gt;
&lt;col width="45%" /&gt;
&lt;col width="45%" /&gt;
&lt;/colgroup&gt;
&lt;thead valign="bottom"&gt;
&lt;tr&gt;&lt;th class="head"&gt;id&lt;/th&gt;
&lt;th class="head"&gt;start_date&lt;/th&gt;
&lt;th class="head"&gt;end_date&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;NULL&lt;/td&gt;
&lt;td&gt;2019-12-31&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;NULL&lt;/td&gt;
&lt;td&gt;2019-12-31&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Both have the same &lt;tt class="docutils literal"&gt;end_date&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;start_date&lt;/tt&gt; set to &lt;tt class="docutils literal"&gt;NULL&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;These two records will be considered unique because a NULL is not equal
to another &lt;tt class="docutils literal"&gt;NULL&lt;/tt&gt; in SQL, so the two records are considered distinct.&lt;/p&gt;
&lt;p&gt;You can use &lt;tt class="docutils literal"&gt;WITH DISTINCT NULL VALUES&lt;/tt&gt; with PostgreSQL 15 but in my
case I was using an older version, of course,&amp;nbsp; so I needed to use
another option.&lt;/p&gt;
&lt;p&gt;If you want to make sure that &lt;tt class="docutils literal"&gt;NULL&lt;/tt&gt; values are not considered
distinct in the &lt;tt class="docutils literal"&gt;UniqueConstraint&lt;/tt&gt;, you can use the hash function with
the unique=True attribute instead.&lt;/p&gt;
&lt;p&gt;Here is an example of the hash function with the unique value based on
the previous code with the Event class. A &lt;tt class="docutils literal"&gt;sha256_hash&lt;/tt&gt; field which
combines all the fields I want in an hash:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;hashlib&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;json&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;   &lt;span class="n"&gt;start_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DateField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;   &lt;span class="n"&gt;end_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DateField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;   &lt;span class="n"&gt;fancy_field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;   &lt;span class="n"&gt;sha256_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinaryField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="n"&gt;unique&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;   &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;   &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;__save__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__save__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sha256_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compute_sha256_hash&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;   &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;compute_sha256_hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="n"&gt;json_object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;         &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;         &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;               &lt;span class="s2"&gt;&amp;quot;start_at&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;               &lt;span class="s2"&gt;&amp;quot;end_at&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;               &lt;span class="s2"&gt;&amp;quot;fancy_field&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;         &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;      &lt;span class="c1"&gt;# Forces datetime to use timestamp due to inconsistency&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="c1"&gt;# in timezone format.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="n"&gt;json_object&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;start_at&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_at&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="n"&gt;json_object&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;end_at&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_at&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;      &lt;span class="n"&gt;json_repr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;         &lt;span class="n"&gt;json_object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;         &lt;span class="n"&gt;sort_keys&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;         &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;         &lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DjangoJSONEncoder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json_repr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;utf-8&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;sha256_hash&lt;/tt&gt; is unique and shouldn’t allow null values, but with
the &lt;tt class="docutils literal"&gt;blank=True&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;null=True&lt;/tt&gt; attributes, it can have null
values. It’s needed then to populate the existing values if there are
some.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What if there is existing data in the table?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;sha256_hash&lt;/tt&gt; is unique and shouldn’t allow null values, but with
the &lt;tt class="docutils literal"&gt;blank=True&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;null=True&lt;/tt&gt; attributes, it can have null
values. It’s needed then to populate the existing values if there are
some.&lt;/p&gt;
&lt;p&gt;In order to do that, we change the attribute to allow null values :&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;   &lt;span class="n"&gt;start_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DateField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;   &lt;span class="n"&gt;end_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DateField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;   &lt;span class="n"&gt;fancy_field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;   &lt;span class="n"&gt;sha256_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinaryField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="n"&gt;unique&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="n"&gt;blank&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;   &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;   &lt;span class="err"&gt;…&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;After that, we can populate the value with a django command in by
filtering the existing Event table where the field &lt;tt class="docutils literal"&gt;sha256_hash&lt;/tt&gt; is
null, and call the method in order the create the &lt;tt class="docutils literal"&gt;sha256_hash&lt;/tt&gt; value
with the method &lt;tt class="docutils literal"&gt;compute_sha256_hash&lt;/tt&gt; of the class.&lt;/p&gt;
&lt;p&gt;That’s it for me!&lt;/p&gt;
</content><category term="til"></category><category term="til"></category><category term="django"></category></entry><entry><title>DjangoCon Europe 2023: from attendee to organizer</title><link href="https://sarahabd.com/blog/djangocon-europe-2023-from-attendee-to-organizer" rel="alternate"></link><published>2023-06-14T14:36:00+02:00</published><updated>2023-06-14T14:36:00+02:00</updated><author><name>Sarah Abderemane</name></author><id>tag:sarahabd.com,2023-06-14:/blog/djangocon-europe-2023-from-attendee-to-organizer</id><summary type="html">&lt;p class="first last"&gt;Hi there, I hope you’re fine. A few weeks ago, I was at DjangoCon Europe in Edinburgh...&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Hi there, I hope you’re fine. A few weeks ago, I was at DjangoCon Europe in Edinburgh.
I’m not sure I have completely recovered from tiredness, but it was awesome!&lt;/p&gt;
&lt;p&gt;I’m hooked on this event. My first DjangoCon was in 2021 in remote, due to COVID, and many
people told me “it’s really different in real life, you should definitely try once”.&lt;/p&gt;
&lt;p&gt;And… I did!&lt;/p&gt;
&lt;p&gt;I participated in DjangoCon Europe last year in Porto, it was amazing.
I really liked the conference and meeting people, some of them that I have talked to virtually,
so there was real joy seeing them in person. It was awesome. This conference helped me to become
more involved in the community and learn so many things.
To be honest, I don’t have the best English but I was able to understand and be understood.
If you have never been to a DjangoCon, you should definitely go to one. It’s truly worth it.&lt;/p&gt;
&lt;p&gt;What you need to know is that each DjangoCon Europe is run by volunteers, and the chairs have
to send a proposal to the &lt;a class="reference external" href="https://www.djangoproject.com/foundation/"&gt;Django Software Foundation&lt;/a&gt;
(DSF) for approval. This conference almost did not happen if you see the DSF’s post about it.
I didn’t want that to happen so I proposed myself as a volunteer. I joined the current team especially
for the website and be part of the Code of Conduct team 💖&lt;/p&gt;
&lt;div class="figure"&gt;
&lt;img alt="2023 CoC Team, from left to right, Thibaud Colas, Sage Abdullah, me and Tom Carrick holding the CoC Sign" src="../images/coc-team-2023.jpg" /&gt;
&lt;p class="caption"&gt;© 2023 Thibaud Colas CC BY-NC-SA - CoC Team of DjangoCon 2023&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Being an organizer is a different way of fun. You don’t enjoy the conference the same way, it can be
exhausting, but you really enjoy the fact of seeing the conference happening and being a success
especially when you know all things that happened behind the scenes.&lt;/p&gt;
&lt;p&gt;When you look at people:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;meeting and laughing together&lt;/li&gt;
&lt;li&gt;finding their future job&lt;/li&gt;
&lt;li&gt;finding new friends&lt;/li&gt;
&lt;li&gt;finding help for a specific project&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It's a priceless joy ✨&lt;/p&gt;
&lt;p&gt;I learn many things by being “on the other side”.&lt;/p&gt;
&lt;p&gt;I didn't understand how hard it is to get a visa depending on the country you're coming from.
The rules are always different. I didn’t imagine how it can cost so much to host an event
virtually when you have limited funds. Each detail counts, when trying to make the best event for everyone.&lt;/p&gt;
&lt;p&gt;I’m really glad to be part of this community, and I hope to do my best to welcome people
and be friendly as much as I've been welcomed myself.&lt;/p&gt;
&lt;p&gt;If you would like to give back to Django and the community, you should consider DjangoCon
Europe 2024 as a way to do so. Being an organizer or a volunteer is a great way to contribute,
and it doesn't require the ability to code.&lt;/p&gt;
&lt;p&gt;I will end this post by saying that “I joined a conference, I stayed for the community” 💚&lt;/p&gt;
</content><category term="blog"></category><category term="django"></category><category term="djangocon"></category><category term="reflexion"></category></entry><entry><title>Thoughts on DjangoCon Europe 2021</title><link href="https://sarahabd.com/blog/djangocon-europe-2021-thoughts" rel="alternate"></link><published>2021-06-07T12:00:00+02:00</published><updated>2021-06-07T12:00:00+02:00</updated><author><name>Sarah Abderemane</name></author><id>tag:sarahabd.com,2021-06-07:/blog/djangocon-europe-2021-thoughts</id><summary type="html">&lt;p class="first last"&gt;Hi there, it has been a while since my last post, but I' m now returning from a great conference: DjangoCon Europe. It was my first virtual…&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Hi there, it has been a while since my last post, but I’ m now returning
from a great conference: DjangoCon Europe.&lt;/p&gt;
&lt;p&gt;It was my first virtual conference. Thanks to the organizers, it was
well done despite the difficult circumstances. We had a
&lt;a class="reference external" href="https://gather.town/"&gt;gather.town&lt;/a&gt; to meet people, talks hosted in
loudswarm, which worked great! It was very interesting. There were great
talks and met amazing people!&lt;/p&gt;
&lt;p&gt;I’m also exhausted lol. I guess it’s another experience as I imagine and
due to the return of people who did it in real life. I hope to have the
ability to attend to another one in person. As people said, you come for
the syntax and stay for the community!&lt;/p&gt;
&lt;p&gt;I gave my first lightning talk at the DjangoCon: “Run Django tests with
GitHub Actions” which was a little introduction to GitHub Actions and
how to use it with Docker services. I’m completely nervous about things
like that but I did it. I’m happy I received some positive feedback. I
know also what to improve if I choose to undertake the experience again
🙂&lt;/p&gt;
&lt;p&gt;If you have one in mind, go for it. You will never regret and it’s a
good experience. You will help someone or make someone discover
something that you didn’t imagine you could. For the sprints, it was
complicated for me to manage the two days, but I was able to be mentor
for DjangoGirls on Saturday. It was a good experience for me.&lt;/p&gt;
</content><category term="blog"></category><category term="django"></category><category term="djangocon"></category><category term="reflexion"></category></entry><entry><title>How to create Github Actions to run tests with services ?</title><link href="https://sarahabd.com/blog/create-github-actions-with-docker-services" rel="alternate"></link><published>2019-11-05T22:12:00+01:00</published><updated>2019-11-05T22:12:00+01:00</updated><author><name>Sarah Abderemane</name></author><id>tag:sarahabd.com,2019-11-05:/blog/create-github-actions-with-docker-services</id><summary type="html">&lt;p class="first last"&gt;I’ve been digging GitHub Actions since I received access to the beta. GitHub Actions is generally available since November 11, 2019 and I…&lt;/p&gt;
</summary><content type="html">&lt;p&gt;I’ve been digging GitHub Actions since I received access to the beta.
GitHub Actions is generally available since November 11, 2019 and I can
explain to you. 🎉&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="https://tkt.paris/comment-creer-une-action-github-pour-tester-son-application-avec-des-services"&gt;French version of the article&lt;/a&gt;  right
here.&lt;/p&gt;
&lt;div class="figure"&gt;
&lt;img alt="Photo of tree of a project with the commits and a graph Git with three branches" src="https://cdn-images-1.medium.com/max/1024/0*dcmLNHncSQ4306nX" /&gt;
&lt;p class="caption"&gt;Photo by Yancy Min on Unsplash&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="what-is-it"&gt;
&lt;h2&gt;What is it ?&lt;/h2&gt;
&lt;p&gt;Github Action is a solution for continuous integration and continuous
deployment (CI/CD). It’s a new feature from Github, which is displayed
as a tab in your repository. Its operations are triggered by &lt;strong&gt;Git
events such as a commit push&lt;/strong&gt;. In order to create a new sequence of
events to be run on a commit push, we must create a set of commands
which will be carried out according to the specifications of the
project. This service is designed to perform processes automatically and
continuously for collaborative work on a Git repo once implemented. It
should be noted that Github Action is based on Docker, so it’s
recommended to have some knowledge about it to use it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="write-your-action"&gt;
&lt;h2&gt;Write your action&lt;/h2&gt;
&lt;p&gt;An action contains several elements necessary to perform a process: the
&lt;strong&gt;on&lt;/strong&gt; event that corresponds to the Github event: push, pull request,
etc. During the beta however, only the push and pull request triggers
are available.&lt;/p&gt;
&lt;pre class="code yaml literal-block"&gt;
&lt;span class="nt"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p-Indicator"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="p-Indicator"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;pull_request&lt;/span&gt;&lt;span class="p-Indicator"&gt;]&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;It is of course possible to define the scope of your action, so it does
specific tasks on certain branches of your repository but not on others.
For example, this may include automatic deployment to a server from the
staging branch but not from the dev branch.&lt;/p&gt;
&lt;pre class="code yaml literal-block"&gt;
&lt;span class="nt"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nt"&gt;push&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nt"&gt;branches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;staging&lt;/span&gt;
&lt;/pre&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;Then we have the &lt;strong&gt;jobs&lt;/strong&gt;. In practice, a job is a series of steps
performed in an orderly manner. It has 2 important elements: the
environment and the steps to be taken by the service.&lt;/div&gt;
&lt;div class="line"&gt;The &lt;strong&gt;runs-on&lt;/strong&gt; parameter defines the environment in which the action
is performed:&lt;/div&gt;
&lt;/div&gt;
&lt;pre class="code yaml literal-block"&gt;
&lt;span class="nt"&gt;runs-on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;ubuntu-latest&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;There are several possible virtual environments for the execution of
your action, this can be useful so that it corresponds to the
specificities of each one. From Ubuntu 19.10 to Windows 2016, you have
the choice 😉&lt;/p&gt;
&lt;blockquote&gt;
It should be noted that each job is performed in a new instance of
the virtual environment.&lt;/blockquote&gt;
&lt;p&gt;So if you want to perform a series of actions with a link between them,
you may want consider doing it in the same job. But it is possible to
create job dependencies with the &lt;strong&gt;need&lt;/strong&gt; parameter:&lt;/p&gt;
&lt;pre class="code yaml literal-block"&gt;
&lt;span class="nt"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nt"&gt;job1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nt"&gt;job2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nt"&gt;need&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;job1&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;In this case, job2 will only run when job1 has been completed.&lt;/p&gt;
&lt;p&gt;Then, we have all the steps to perform during the process. With a view
to continuous integration, the aim is to launch the tests automatically.
However, a number of elements must be defined before the tests can be
performed!&lt;/p&gt;
&lt;p&gt;This set is defined by the keyword &lt;strong&gt;steps&lt;/strong&gt;. Each step requires at
least one element to be performed, i.e.&amp;nbsp;one of its elements:&lt;/p&gt;
&lt;p&gt;the &lt;strong&gt;uses&lt;/strong&gt; keyword to use a specific element:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;a public action&lt;/li&gt;
&lt;li&gt;an action in the same repository&lt;/li&gt;
&lt;li&gt;an action on the Docker Hub or on the Docker public register&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;p&gt;the &lt;strong&gt;run&lt;/strong&gt; keyword to launch a command in bash (knowing that there are
several ways to execute a command if necessary)&lt;/p&gt;
&lt;p&gt;Finally, we associate the parameter &lt;strong&gt;name&lt;/strong&gt; to know which step it
represents. An example being always more meaningful, so here is a job to
test a Django project:&lt;/p&gt;
&lt;pre class="code yaml literal-block"&gt;
&lt;span class="nt"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nt"&gt;tests&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nt"&gt;runs-on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;ubuntu-latest&lt;/span&gt;&lt;span class="w"&gt;

   &lt;/span&gt;&lt;span class="nt"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;actions/checkout&amp;#64;v1&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;Set up Python 3.5.7&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;actions/setup-python&amp;#64;v1&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nt"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nt"&gt;python-version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;3.5.7&lt;/span&gt;&lt;span class="w"&gt;

   &lt;/span&gt;&lt;span class="p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;Install dependencies&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;pip install -r requirements.txt&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;Run tests&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;python manage.py test&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Here the job tests consist of:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;install Python 3.5.7 on the Ubuntu environment&lt;/li&gt;
&lt;li&gt;install the dependencies&lt;/li&gt;
&lt;li&gt;start the tests&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For tests in real conditions, a database is needed, hence the
&lt;em&gt;implementation of services&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="add-a-service-to-your-action"&gt;
&lt;h2&gt;Add a service to your action&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;How do we do it?&lt;/em&gt; Very simple, it is similar to the definition of a
service in a docker-compose.yml but with far fewer parameters.&lt;/p&gt;
&lt;p&gt;We use the keyword &lt;strong&gt;services&lt;/strong&gt; with :&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;the definition of the Docker image to be used&lt;/li&gt;
&lt;li&gt;the list of ports to be exposed of the service&lt;/li&gt;
&lt;li&gt;a list of environment variables&lt;/li&gt;
&lt;li&gt;a list of volumes&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;Not all of these elements are required but good to know.&lt;/div&gt;
&lt;div class="line"&gt;In concrete terms, it looks like this, for a Postgres service:&lt;/div&gt;
&lt;/div&gt;
&lt;pre class="code yaml literal-block"&gt;
&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;postgres&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;env&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;postgres&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;postgres&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;POSTGRES_BD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;postgres&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;5432/tcp&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nt"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;--health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;We need the Docker image to launch, the port to expose and the name of
the service. There is a way to transmit environment values or Docker
options as shown in the example above. Sensitive values can be defined
with &lt;a class="reference external" href="https://help.github.com/en/github/automating-your-workflow-with-github-actions/virtual-environments-for-github-actions#creating-and-using-secrets-encrypted-variables"&gt;secret
key&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In addition, it is sometimes necessary to require a service status
feedback to establish a connection. Therefore, an element is defined
that checks the health of the service to know when it is operational
(also called a health check). I took up the example made by Chris
Patterson and &lt;a class="reference external" href="https://dev.to/mscccc"&gt;Mike Coutermarsh&lt;/a&gt; for
PostgreSQL.&lt;/p&gt;
&lt;p&gt;In case you don’t have a health check available, we pause the process
execution with the command &lt;strong&gt;sleep&lt;/strong&gt; , yes it’s not great, I grant you…&lt;/p&gt;
&lt;p&gt;All this is very good, but we have to make the link between the service
and our application. We will do it through the port and for the host it
will be &lt;em&gt;localhost&lt;/em&gt; since the service is executed directly in the Ubuntu
machine in our example. Otherwise it would have been the name of the
service.&lt;/p&gt;
&lt;p&gt;In the previous example, the machine port 5432 is randomly assigned a
free port and accessed as follows:&lt;/p&gt;
&lt;pre class="code yaml literal-block"&gt;
&lt;span class="l-Scalar-Plain"&gt;${{ job.services.postgres.ports[5432] }}&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Nevertheless, it can be assigned in a fixed way:&lt;/p&gt;
&lt;pre class="code yaml literal-block"&gt;
&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;5432:5432&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Here, we have the port 5432 of the service related to the port 5432 of
the machine defined in the action.&lt;/p&gt;
&lt;p&gt;The following workflow is implemented:&lt;/p&gt;
&lt;pre class="code yaml literal-block"&gt;
&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;Test Workflow&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nt"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;push&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nt"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nt"&gt;tests&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nt"&gt;runs-on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;ubuntu-latest&lt;/span&gt;&lt;span class="w"&gt;

   &lt;/span&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;postgres&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nt"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;postgres&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;postgres&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;POSTGRES_BD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;postgres&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;5432:5432&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nt"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;--health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5&lt;/span&gt;&lt;span class="w"&gt;

   &lt;/span&gt;&lt;span class="nt"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;actions/checkout&amp;#64;v1&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;Set up Python 3.5.7&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;actions/setup-python&amp;#64;v1&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nt"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nt"&gt;python-version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;3.5.7&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;Install dependencies&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;pip install -r requirements.txt&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;Run tests&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;python manage.py test&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;In our example, we still need to override the service values in the
Django settings.py for the connection to the PostgreSQL database.&lt;/p&gt;
&lt;p&gt;Then the trick is done, just push some code and hope it works. 😉&lt;/p&gt;
&lt;/div&gt;
</content><category term="blog"></category><category term="github-actions"></category><category term="testing"></category><category term="docker"></category><category term="howto"></category><category term="django"></category></entry></feed>