Skip to content

Instantly share code, notes, and snippets.

@brylie
Created November 28, 2023 17:47
Show Gist options
  • Save brylie/b48777e1ad13cd47343170e9fa111dba to your computer and use it in GitHub Desktop.
Save brylie/b48777e1ad13cd47343170e9fa111dba to your computer and use it in GitHub Desktop.
Code With Brylie - e38
Hello and welcome to an open source live code hangout where today we will be working on the Western Friend website.
I'm going to look in our issue queue for some kind of top priorities. There was one I think relating to pagination which somehow didn't get displayed on our project. So I assign myself to this and it's a bug. It's either not working or hasn't been implemented. I think it might have been an oversight but I don't know yet. I think the original plan perhaps was to display all the items and then add pagination post launch. I don't know. I don't know. That wouldn't really make sense because the search page could display a lot of results. It makes me curious how many other issues do we have in our backlog that aren't assigned to a project. Let's see if there's a way I can negate filters.
Feature request. This has been archived. No project.
Let's see. Okay.
Looks about right. Yeah. Okay. Let's do a small amount of backlog grooming here.
There we go. Actually, then I can add them all at once. That should work. There it goes. So we're using this new GitHub projects interface, relatively new and under continual development. At first I was hesitant to use it. It seemed kind of half-baked. Sometimes awkward. It was difficult to synchronize the issues. I think they've done a lot of improvements on this.
So let's see. It's pretty nice that it allows custom fields sorting. It would be nice if you can sort by multiple. I have a sub sort. Priority and size is a very common one but you can also use these. It's another BU configuration. You have configurable fields. You can group items. So here we've got iteration grouping and then no iteration. Sort. Now this would be nice where I could have if I could have a sub sort with alt just like the secondary search so I can. Wow, that is cool. Alt would be I would say size for the secondary support. Sort. Yeah. The key and this is interesting. They don't have to be alphabetical but let's see how that comes out.
Medium, small, medium and large. That looks good. So it kind of lets me do a bit of triage. If there's something really high priority, you know, we want to get to those first. If we have a bunch of medium priority things, how do I choose? Well, perhaps I can put out the small fires or do the small work efforts first. Wow. So that's nice. That's a nice enhancement. I also learned you can copy and paste. So when we want to or select multiple fields and it's like a spreadsheet. So you can apply content like label sets to multiple fields simultaneously. So for example, I can copy this and paste it here. Copy and paste this one. Let's assign to Mary.
It's non trivial. This is not a good first issue. I'm going to paste this in and remove the good first issue. But help would be appreciated. So I'll label all these with help one time. This is an enhancement though. In any case, the main goal here is that we have everything prioritized. So it looks like those new issues I added and don't have priority in the one problem is if I change the priority here, let me see, edit the title. This metadata here is verbose. Oops. That's the button I'm looking for. When I change the priority here, let's say low, it jumps it. If I had changed it to medium or high, it would jump the screen all the way up here. So I understand that that's so you don't lose sight of the change you just made. That makes sense from UX perspective, I guess. The problem is if I'm going through bulk applying these, I have a different view set up for that basically. Search pagination not displaying. So that's what I'm going to work on now. High priority. Search highlighting suffix, low, extra, extra section.
Basically, if it's not a bug at this point, I'm going to give them all equal priority of low or
significant user experience enhancement. These are all stylistic and cleanup.
That could be a bug. This is style. Those are nice to have docstrings. Those are nice to have also. This is no longer relevant. So we don't really do that. Okay, so a little bit of backlog grooming. Nonetheless, I think it's the right time for us to move over to using this GitHub projects. It's getting better. I won't go through on stream and estimate these. So let's go ahead and take this search pagination into the current iteration.
Since it's a bug, I'll refresh my IT and then we'll get into the code. Just 10 minutes of backlog grooming to start the session.
Alright, so we have a search page on the website. If I search for something here, for Quaker for example, we get some results and I believe that being a Quaker website there should be probably more results than this and in order to access those, I think there's a missing paginator here.
So I'm going to take this opportunity to improve
take all of these search iterations, sorry, the pagination-related ones into the current sprint.
That's actually not trivial.
Nevermind that one.
But we'll take a look at our pagination widgets, see what code we can share and what we can't.
I think what we're gonna do is create a shared pagination template. So a component that renders the HTML,
but have to have the duplicate pagination logic to construct the paginator.
Each place we need pagination
because of some warnings I'm getting in the console recently.
So first let's search for pagination.
Paginator.
So we have events,
magazine,
events and magazine.
And nothing in the,
nothing in the search module for some reason.
Oops, that's actually not what I wanted to do.
So this looks good. And as long as we're passing a paginator into the template context, I think my first idea of having a shared template component will work.
That way at least our pagination is consistent. So in the advanced page, here we go.
You can see we've got this paginator.
And it's doing its logic here.
And it's keeping track of the page number.
So since this is in the events index page, this markup, other places in the site like the library index,
that define their own pagination might be inconsistent. And so we kind of end up with a bit of a mess.
And it can be confusing for users.
And I'll be right back.
(keyboard clattering)
Okay.
So that said,
I will take one of these and create a nice template out of it. I'm pretty sure. We have pagination on the deep index page as well.
Memorials, all these are using pagination. I have this pagination helper
that is supposed to take one step in the direction of having a shared pagination module. But I'm getting console errors about sending
an unsorted query set to a paginator. I think that the, for some reason the type hinting can't track whether or not the query set has been sorted when I pass it into the function. It loses the thread. So I don't think I'm going to be able to share the logic,
unfortunately. So it won't be truly a component. But let's go to the search real quick
and just see what the search view is doing.
So if we've got a query, get the results,
and paginate them.
(clicking) They should be getting sent to the template then.
(clicking)
Interesting. So,
start the development database.
At this point, I'm going to unassign
Raj and assign myself.
It's been a little bit.
(clicking)
(clicking)
Okay, so if I search for something, test,
we have some items, but no pagination.
So,
let me double check. (clicking)
We have our search block here.
Oh yeah, I'm sorry, this is right here.
So we're just displaying each result, and we're actually... (clicking)
We can display one item per page.
It is paginating, but the interface has changed. Okay, so this is where I think the common paginating widget.
And I think I changed the name, and that's about it.
Let's see, for result, no page.
Strange.
(breathing heavily)
(clicking) All right.
So what we'll do is create in our core
templates, paginator.
(clicking) And we'll go to the library,
which has the most,
I would say comprehensive paginator. So if I go to the other content, media library,
with this really nice paginator here, it works, it's been tested.
Got some weirdness because of the wrapping. I should put a non-breaking space there.
But I can fix that in this pull request. And we'll grab this markup.
So there are no library templates.
Library index page, and it's this paginator.
So first we see if there's an item and it's gonna iterate over those.
So this is a paginator. I can just call it if paginator, for example.
But what we're gonna then do is,
so first we display the items, then we render the pagination. We should take into consideration ARIA labels, but make it generic.
So it's this whole if paginated items.
Where is this ending here?
(clicking)
And what we'll do,
(clicking)
we should be able to then load that, include that in say paginated items in our library item.
(clicking)
(clicking) Current query string, it's current query string.
Now to avoid confusing myself, I need to just close the live server.
(clicking)
Yeah, let's see, okay, so how do I include?
(clicking)
(clicking)
I've got the current, the following template, partial and Django, yada, yada, yada. I'd like to include that template in another template language, a template and pass the context variables, paginated items and current query string. So it is include,
paginated items and current query string variables are available in the context of the template where you're defined, including pagination, they will automatically be available, okay. That's a bit tricky, it's implicit. Is there a way to explicitly?
(clicking)
(clicking)
So is there a way to explicitly provide those variables, such as an alternative to include or,
the odd to the end include tag,
or passing them as arguments to the include statement.
You can explicitly provide context variables to an included template in Django while the include tag automatically has access to the current context, you can also pass specific variables to the template being included. This is by using the with keyword, alongside the include tag. Yeah, I think that this implicit context is gonna be confusing, but if I use with, then we'll be good to go.
There we are, we have with and the paginator works. And the key is, now if I select an audience, for example,
I got no pagination there, audience one, let's clear that. Let's see if there's one I can do.
A lot of them, well,
the one with the and the title, there we go.
So we have this query string up here.
Now it should be passed along. When I go to the pagination page four contains the, so that's working, that worked.
Now we have a common template with explicit arguments.
Current query string is only used on this page, but will probably be useful on the search page as well to preserve the search term across the pages.
I think let's find out.
Let's see, can I fix this non-wreaking space thing?
So now we have one template, so I fix it in one place, it fixes it everywhere, nice.
All right.
Oh, wait, I think non-wreaking space should go here.
That looks good.
Yeah, so it's all, it's a little bit cleaner that way.
It's not perfect. These could actually be wider, it looks like, on this breakpoint. But let's continue focusing only on pagination here. So now we've got a unified paginator. I'm not gonna commit that.
But this get paginated item here, let me see if I can clear out that.
Console, I'm gonna run this. This has been complaining.
So we've got the Wagtail snippets thing that we worked on in the last session.
Maybe this get paginated items is also okay if I can share this function.
Because this wraps all my pagination logic in a single place. That's again, it's maintained.
Once if I fix something in one place, it fixes it everywhere.
So how did,
how did I get this error? I think it's,
when I run the tests.
Somewhere along in the tests, it'll have the notice that comes up. It's a bit annoying. I could probably live with it though. If I could suppress it, that would be even better.
I would like to have a single unified, get paginated items function.
It just takes a query set.
Perhaps I can, perhaps there's a sorted query set.
Yeah, it's this error here. And I've got a feeling test. Oh no.
(sighs)
The warning you're seeing, unordered object list warning is Django's way of telling you that you're trying to paginate a query set that hasn't been explicitly ordered.
This can lead to inconsistent pagination results
because the order of records in an unordered query set is not guaranteed to be consistent across database queries.
To address this, you should explicitly define an order for your query set before passing it to the paginator. This is done by using the order by method on your query set. Order by method allows you to specify the field or fields that you want to order your query set.
Yeah, so maybe it is already on the query set in most cases, just in the test case,
here, whatever is happening.
We're not using the paginator correctly. Oh yeah, and the test is, they're failing because I changed the pad number of items per page.
Okay, but that's not a big deal. An order object list. Pagination me yield, yes.
So,
cast models users. (keyboard clicking)
So, this query set might have a property on there.
It says whether it's sorted.
Hey, thanks, Ancapster. Welcome to the stream. How are you doing today? Thanks for the emoji bomb.
Subscribe.
Let's see where we're using this. Perhaps I can find this, get paginated items. We're mocking it here.
Okay, six to go. What is it?
Six, around number of subscribers or something.
I haven't been keeping track, but thanks for pushing it forward.
Oh yeah, wow.
I forgot a headset, a goal of 150, thanks.
Yeah, so I think this is the problem. If I just, yeah, I'm just grabbing the user objects. Order by, might fix the problem there.
For all of those tests.
Okay, cool. What'd you have for dinner?
It's dinner time when you're, where you're located. It's past dinner time here. It's past my bedtime actually, but I couldn't. I slept during the day I had a problem.
I was sleep deprived. All right, so self users are now paginated. I think that'll get rid of this particular error.
Okay, Brazil, very cool.
audience member coughs)
Yeah, how's the weather there? It's summertime there.
Probably it's always like summertime there. I don't know. (laughs) Amazonia, okay. Is that, that's in central Brazil or where's that located?
Yeah, 5.30, okay. 17.30, so yeah.
So if I stream it this time, then people in the Americas can hang out.
Okay, let's rerun just this test here. So we got the tests is in pagination tests.
Keep TV.
Pagination tests.
Yes, that got rid of the error. Okay, so that was it. Just explicit order by. Well, this is great. I'm glad that I can actually have this common
pagination helper class. This was just a guess. I was seeing if that was even possible. So query sets will indicate if they are sorted or not.
Very cool, let me just replenish my tea. I'll be right back.
Okay, Wisconsin, yeah. It's same time zone, but like pretty far away. (laughs) A whole continent away, man. It's a long trip. I'm in Finland and I'm originally from Kansas. It's probably as far from Brazil to Wisconsin as it is from Finland to Kansas.
Okay, so now that I've got this in good shape, where I know that I can use my paginator HTML that worked.
And I have a pagination helper here in pagination helpers. So actually, since I've got pagination, which I completely forgot about,
I'm gonna move my pagination template there.
Or a paginator template.
And continue with this pull request. Pagination template, paginator.
See the library item should run the server. Library page should still work.
I've got the paginator there.
Oh.
Template does not exist. Okay, so either templates.
(sighs)
The template is in the right location.
Maybe the, I did just start the server again, so it should pick up, change it to the file system.
Possibly.
Does Django deal with authentication or authorization? Single sign off, for example. Yes, it does.
By default, Django includes
authentication with group-based access control
for authorization.
And then for single sign on, there are really good modules like Django all auth.
I'll just show you the user authentication. It's built into the framework. It does a lot of work for you. That's the reason I'm using Django is the heavy lifting it does for me. I don't even know I need until I need it, then it's already there. Like storing password hashing and security around that. So you have a basic permission system. You can add people to groups. It'll handle the security of passwords and generating forms, but you can swap it out. And it has some things about security that are bonuses, like checking the strength of passwords,
keeping people from brute forcing. And then OAuth, for you mentioned single sign on. Even down to row level or object level permissions. It's baked in. Django product for testing, my background is in Next.js. Yeah, you'll be really surprised at the difference
of the developer experience when you use a framework like Django versus Next.js about what it includes, what the word framework means in the context of Django in the Python ecosystem. It's a day and night difference. It's an immense difference.
And the phrase that we use is called batteries included. That it just has like so many things that you don't even realize you need until you do. And then they're already there. And there's conventions and documentation to describe how they work. And if you don't need them, then they won't get in your way because you just don't import it. You don't use that part. If you don't need template rendering, if you're using React server side components, then you can skip the template language. But I really recommend even just going all in on the Django template language. And there's a lot of value in that as well.
Yeah, so it'll be cool to take the way you learn from Python and see if you can find an equivalent in JavaScript world. The closest I've found is Nest.
But even it pales in comparison to Django.
It has some nice features built in, and it's trying to be a full fledged framework.
But it's still really low level. (keyboard clicking)
Yeah, I don't have a particular preference aside from I'm getting out of the JavaScript ecosystem as much as I can.
We did build a product with Meteor JS.
That ran for several years in production. And it was a good experience overall. We got the product built and launched in people's hands and it had an impact on people's lives. But the maintenance it turned out and some of the design decisions that they made with tying Meteor JS to MongoDB, for example, and going this route of ignoring the fact that we need schemas and data migrations and relationships and things like that typically.
And these types of applications was really a big mistake. And led me back to Django.
Yeah, let me know if you're exploring it a bit.
I can check out any open source projects you're working on. If you'd like to get your feet wet with Django, I do have several tasks you can try.
This project is open source, for example, this Western Friend project. And we've got several mini tasks actually. Let me save this view real quick.
That are flagged for good first issues.
This is one that we're really focusing on.
So if I just show you the repo, for example, WF website, we just launched this website. But I also have a couple of other Django projects I'm working on and there's a lot of, I do the same sort of stewardship.
When I have an open source project, I label a bunch of them with good first issues. And these are things that I think are kind of small tasks that let you get some experience contributing to an open source project.
Yeah, and some of them are really small. Or some of them might even already be done. These ones that start with parentheses, P-Y-L-E-L-F-L-K, Flake, Python, these are kind of style and level changes that would just let you see, here's how to run a project, here's how to change the code and commit those changes to an open source repo without much getting into the internals of how the project works even.
And these came from a static analysis tool we were using called DeepSource. Some of these are already resolved, but I can't remember which, so I need to close some of these.
Adding a docstring to a function.
By the way, do you use like chat GPT or anything like that?
What's your experience with those kind of code and assistant tools like this one or GitHub Copilot, which I'm gonna be using, I'm pretty sure during this session.
Okay, so we've got our helper.
Perplexity and find, okay.
AI search engine and pair programmer, nice.
Excellent, and do they embed directly in your IDE?
Cloud to or GPT back in, hey, that's cool.
Nice, what's the pricing?
Perplexity is more general. I think I'd heard of this, it's like a knowledge search, I think that's hence the name and somebody was describing is using it like a for summarization.
Then they started building knowledge graphs and they were like finding that perplexity came up really short and was providing really generic responses compared to their knowledge graph or something like that. I was watching some YouTube video on that.
Future PDF for AI training stuff, thanks, these are great. (keyboard clacking)
The largest AI tools and software directory.
Any like, what's the organization behind it? I was looking for the footnote, favorites deals, advertise resources, subscribe.
Day and night mode, nice.
Yeah, I don't even know what I would use. We're thinking about making this open source game.
Like an educational adventure game. So one of them was we were like, hey, how can we make consistent characters in game art?
Yeah, this is the one we settled on. We're like Leonardo AI. We're using, oh shoot, I keep forgetting the mid journey. Mid journey, it's really good. But the interface for mid journey is Discord and it's like, ah, that's like using a command line tool. It's like, okay, it's powerful, but give me something that's more direct manipulation and tells me what the in fordances are, tells me what I can do with the tool.
Not having me figure out esoteric flags and watch YouTube videos about what particular,
just all these weird terminology. I have to like dig up from YouTube tutorials and stuff. Leonardo kind of gives you really good user interface there.
So I think that's the one I would bet on Leonardo AI if I were to say, you know, who will be successful in the upcoming five, 10 years.
And companies who follow that, you know, this is nice. It's kind of almost like an airline pilot user interface. Leonardo's a bit more refined.
The chat interface for chat GPT though is really good. It lets you do natural language, but then when you start to add feature flags into these natural language statements, that's where the user experience breaks down.
But yeah, future P this is really great. Thanks for showing me that.
And there's a huge, a lot of innovation in this space.
Yeah, okay. Well, Python machine learning. Yeah, I'm gonna be doing a bit of, do you like data visualization by any chance?
I'll put these in my back of my mind, but I don't know if I'll bookmark. I don't really use bookmarks.
Yeah, I put paper.
Yeah, well, that's easy to do. That's a really big habit I have struggled with for many years. In fact, it took me over 10 years to go from delivering Chinese food and reading about Python between deliveries to actually writing my first application, web application.
And then 10 more years to like be able to have
launched a couple projects and work now full time as a software engineer.
Yeah, it's been a while. Didn't realize that. Yeah, thanks. It was kind of, it was cool. I've always, I liked Python. I like Monty Python and I think that's what drew me to the language and then heard good things about it being kind of friendly, too easy to learn. So I just was reading Python for dummies sitting at this table in Overland Park, Kansas in between Chinese deliveries and owner let me do that. And sometimes that would help with other things like
random tasks, but they were actually nice enough to just let me read for a while.
But I didn't do anything with it. I just procrastinated like big time.
I was starting to grok it, but in order to really understand you have to do it. And that's why it took me another 10 years. Then Meteor JS came out and that actually catalyzed my interest again. And I just started building with Meteor JS.
And that's when things really accelerated when I started building.
So yeah, do you have any ideas? Yes, starting is really tough, isn't it? There's a lot of inertia and fear and self doubt those kind of things.
That's why it's good to start small. I'm trying to help some other people here in my neighborhood get started out as well, but maybe that they'll have a quicker ramp up time.
Tutorial, yeah, and you can just watch another YouTube video and another one and another and not really do anything.
It's interesting, I probably have heard that phrase, tutorial help.
Yes, okay, so then what was the problem here? I think I didn't register this app properly with my settings. Maybe that's the problem. I don't know why, it's just a regular Python module and I think Django's not picking it up
as a source of Django app, as a Django app. So that would be under pagination. Let me just double check.
PayPal.
That's the case.
Pagination, is it?
Yes, so now if I save, that should be all that's needed for this template to be found. Yeah, very cool.
All right, automon.
Oh, I see, yeah, I learned about Twitch. So LMAO is a filtered term.
All right, yeah, so what are you gonna build? Whoops.
What do you think you'd like to build?
I do, I have done a lot of work with data, a little bit of work professionally with machine learning,
mostly with data pipelines and data visualization.
And I'm gonna be working on this,
stream this channel with some data visualization projects coming up in the next, like over the next, it's gonna be, I'll start soon and it's gonna be a long project, like at least one year.
The project I'm working on now, we've been developing for five years and we just launched it. Ton of tool to learn. Yeah, that's another thing, you get this paralysis because you have so much. It can feel like everything pressing down on you is like, where do I even start?
Django is a really good start. The reason is you get right to the heart of your data model and you're working with requests and responses.
Yeah, Python is great and what you learn is transferable and in fact, if you go on as a JavaScript engineer, you will look for Pythonic experience in the JavaScript ecosystem and maybe we'll help catalyze that.
All right, so next paginator.
So use unified pagination. So that's working, that's done. Search and essentially,
here's where I need to pass the query string.
Can fix that again, the search should work.
Yeah, that's an interesting point
which we could have more time.
Yeah.
But we don't and so we have to learn time management. That's something I've struggled with like super
through my whole life, time management.
I get distracted.
I have ADD, I was diagnosed with ADHD. I think it's now just ADD. I don't feel so hyperactive but very distractible or if I'm really interested in something, I can be like zone, in the zone on that thing.
I get that with music and with code sometimes but in order to show up and like start the thing, that's where I bounce around and I have to like almost just have a routine like this live coding.
I just say, okay, after work on Mondays and every other weekend, I'm gonna sit down and do live code. So I block that space
and then the next big challenge is like, what do I do during that space?
So once you've got the ball rolling, you start a small project, then there's lots to do. I have 55 things that need done. So choosing something that actually is,
well, it's still a bit tricky but that's when I use prioritization
and that's where we've been doing this backlog grooming and things like that. So this is something I've just learned over years and practiced this quite a lot now professionally because we have to prioritize, we have to manage work that comes to us. So we've got like 80 items, how do I choose the next one? Well, we use prioritization, T-shirt sizes,
small, medium, large size and high, medium, low priority.
And that's sort of like an Eisenhower matrix in a way, but urgency and priority would be the Eisenhower matrix.
Yeah, and I just learned today that you can dual sort on GitHub issues. So you could even set up like a personal repository for like your own life stuff,
yeah, or use something like Notion or something, of course, and just apply the same methodology and use T-shirt sizes for how big of a thing it looks. If it's a large or extra large T-shirt size, you might be able to break it down into smaller chunks and prioritize and categorize things. Just this is what I do for work. This is what I do for school. This is what I do for personal studying or my hobby, or if I wanna make a musical album, you have categories of projects. Obsidian, yeah, I was checking that out too.
And it's got the Obsidian I like because you can sort of synchronize it with a Git back end if you want. So all your notes can live on GitHub.
audience member speaking)
Yeah, that one I have checked out a bit. One thing I like about Notion
is the real time collaboration because I'm sharing this with people. And also I like the Notion AI. Having a large language model inside of my Notion actually has saved me, has helped me out quite a lot because I use it to draft articles and things like that. And I'll use like Chad GPT on the body of the article, but Chad GPT's writing style sometimes is weird.
So I'll use it in Notion uses Claude, Anthropic Claude and it has, I can tell it to simplify or make the writing more straightforward and things like that.
It's not perfect, but yeah, Obsidian is huge. And they're probably looking at Obsidian AI
or something like that, right? I like this Knowledge Graph. This is something I've been really interested in lately is your Knowledge Graph,
but building not just what links to what, but having an ontology of like particular types of links between entities like the Wiki Data Initiative.
Canvas is pretty cool. And the plugins are so probably already a GPT plugin for it, I bet.
Synchronization is cool. Do they have real time? And I wish their publishing was a bit cheaper. It's like all eight per month. Okay.
That's not so bad actually.
But if I wanna publish multiple sites with the same database with my Notion, I have multiple shares. I share with multiple people.
Up to four gigs.
And then I have a theme and domain. So this would be a single site. No, not bad though.
Yeah, I agree. I really like Obsidian. I haven't given it as much attention.
You have to make your own vault and then you can publish it. Can you publish it like on GitHub pages or something? Or make my own vault, Selective Sync. And collaboration is there.
And if I wanted a shared vault.
And I have 10 bucks a month.
And does each person have to pay?
Canvas is cool.
Sounding, I like that. I like these nonlinear brain graphs and the concept maps that you can do.
Yeah, pretty cool. And I like that it's open source.
Open source on GitHub.
These parts of it are.
Fusion Mastodon.
Plugins, create your own plugins. You use the plugins from the community. A lot of integrations. Yeah, and I bet, man, it's under crazy active development. Yeah, these are things that Notion doesn't do. But in terms of collaborating with other people, I'm gonna kind of stick with Notion for that. For our little startup business, we're gonna use Notion. We've already got an agreement, but for my own personal note, I might just go back to Obsidian. I don't know.
I'm paying 20 a month right now for a personal Notion with Notion AI.
And the real time collaboration in Notion is actually really cool, because I can be opening it up on my screen and have somebody else opening the same document and we're like editing stuff and synchronizing. That's pretty cool.
Yeah, it's a great way to organize your life and your knowledge. And what kind of widgets does it have? That's a cool thing about Notion and probably Obsidian. They're the block based editing interface. You got some checklist here.
There's plugins probably.
I do like the links. Now Notion doesn't do this. This is totally cool. This is totally cool.
It doesn't really show me the blocks.
Plugins, AI. Let me just see this. AI, Omblay, Chatbot, or GPT.
Prompt engineering research, I'll tell you.
Copilot.
Yeah, I'm sure there's something. Yeah, lots of these. All right.
Yeah, that Notion doesn't do it unless they open. Maybe they have a marketplace, a Notion marketplace or something.
33 gigs of notes and code. You're putting code in there too. This is the thing. I want to synchronize my stuff on GitHub. And I was really trying.
I landed on, let's see, Flutter Friends. What's it called? Quartro.
On Quarto.
For certain types of projects where I want to synchronize on GitHub, boy, this is bright. Can I turn that off?
It's essentially a publishing platform. So it's not exactly the same as what we're using for Obsidian and Notion for, but you can publish books and websites and stuff like that. And write it in, the editing experience is important. So Notion has an excellent editing experience.
Obsidian seems pretty good. User interface looks pretty nice.
Not writing Markdown is a plus, but you still have to kind of do that. Quartro is a Markdown style.
And so it's a bit more for technical people.
But it lets me have a repo and publish for me. And publish books and have them open source and publicly available. And I can still use generative AI. I just have to kind of copy and paste.
It's all right. So this one I like, but I'm trying to publish stuff so other people can check it out, try the code and things like that.
So this is a different use case with the personal notes.
I wrote a book. (keyboard clicking)
Everybody, you think it was? It's live for everybody. Good.
(keyboard clicking)
And Repositories. Oh yeah, Dart for a run, of course it does.
This is written, first draft, published just recently with Quartro.
Pretty good and written primarily with GPT.
But the general idea is kind of helping people learn to program.
And so I want something that I can write almost as fast as I can think.
And publish in a nice form.
Hacktricks. Hacktricks.
Yeah, let's see. So Obsidian.
Because the GitHub thing is a really important thing for me.
And of course I can just use Git. It's just a bunch of Markdown files.
(laughing) But, like I don't want to think about that. Like with Notion, I just write and it's synchronized.
Okay, so this is every X-Man sync. That's cool though.
Yeah, so that's cool. Yeah, so I'll give Obsidian another thought and see how I can balance it. I'm gonna have too many tools.
But just enough.
All right, so I think we're here and we're done.
So, done with the view pie.
So now I just need to, everywhere I was using Paginator,
use our shared Paginator.
Every time I'm generating paginated items, use our shared Paginator and we're good to go. This will take a bit of focus.
So how to tackle it. Well first, we will, I guess I will open up the page. See, where did I get it? The library, yellow templates. So this is my, how I do it right here.
Gotta accomplish some labs here. All right.
Yep, thanks. Hope to see you around and let me know what you're thinking of Django. And if you wanna contribute to some projects, I have some great tasks that I can get you started with.
Thanks for stopping by and subscribing.
Okay, I'll mention you somewhere. Just, let me see if I can say hello.
Oh, thanks, yeah.
See you around.
(clicking)
(clicking) Cool.
Okay, didn't work for some reason.
Not sure why.
But I have mentioned, like that.
Perhaps you have to be in like the group or something. Well darn. (clicking)
Ah, okay.
Apparently not the right one.
It's pretty tricky.
(clicking)
Zero days, four minutes. Zero XR for, zero XRH. Let's just try zero XRH.
Could be zero XRH.
The zero days, four minutes thing I think might have been from something else.
Well then, back to the task at hand.
Okay, okay, zero days, four minutes, one nanosecond.
There we go.
Or what's the, oh yeah, there we go. Got it, security researcher. Yeah, if you wanna check out the security of this website, that would be cool too. (laughs) Snort Social, okay, very cool.
Security researcher, full-star developers. I have a punk indigenous, well yeah, very cool.
Profile picture too, wow.
Snort Social is just mastodon.
Interesting.
(laughs) Ocohost.
Snort's another project. Oh, okay, so it's an alternate visitor. Federated alternative to much more hoozums. I've finally got a blue sky account.
Just before, I've got one on Hacker News, like very randomly in a random thread about SQLite.
And then the same week my invitation was sent from like I had applied months before to get a blue sky one. But I'm also on like Mastodon Network.
Okay, cool, see you around. I don't wanna keep you delayed here.
Oh, okay, they're all private. Some cool stuff there.
Yeah, Hacker Roadmap, cool. (keyboard clacking) Yep, have a great day.
Nice.
Ah, I bet information gathering tools.
Very cool, I don't know how I wanna be a hacker though. I am a hacker, but I'm building my own stuff. Okay, here it is. So we're gonna include the paginator, but I have to be a little bit careful here.
And make sure that I use events
for the paginated items.
And in this case, we don't need the URL string.
(keyboard clacking)
So that won't exist.
Oh, damn it.
Okay.
Now for our model paginated events,
I'm gonna do this in a methodical order. So I wanna do both, just every module I change, I wanna do both changes at once.
Upcoming events page.
So in order to do this, I'm gonna create two separate tabs. One is the right way to do it, where we have made the changes in our library, actually the library index page.
And the other, so this is our reference.
And we're using pagination.
Get paginated items.
So we get the query set with an order by,
the items for page and current page number that needs, okay, this is interesting. I'm parsing it to a integer later. Well, that works. So copy that.
Default value one.
(keyboard clacking)
And essentially paginated events.
All this error handling is done inside.
Get paginated items.
Items for page.
I mean, it's a bit redundant, but okay.
I'll have this placeholder variable.
Oh, there it is.
It's already there.
(keyboard clacking)
And then import.
Yeah, this is more. (keyboard clacking) Less error prone.
So now if we go here to events, whoops.
(keyboard clacking) A lot of news item.
I need to make a database fixture to save myself some time here, but okay. I don't have it. I haven't invested in it. Oh, okay. News topics.
Add child pages should be a news item yet.
And then we'll paginate.
There's the news items. And we'll paginate it to
one item per page right now.
There we go. All right.
Some news is not working.
So events is working.
Paginated items is working.
Ah, I'm in the wrong module. Gosh, it's a bit late.
Here we go.
All right.
So that's events items needs to be fixed.
(keyboard clacking) I think it's what that's, that's where, okay. So for event, and event items, right? Let me see how I did it on the library.
(keyboard clacking)
Okay, page. For library item and page, okay.
(keyboard clacking)
No Western events, okay, there's something. And we'll just go ahead and create a new event.
New event, event one.
Starts today.
Default time zone, publish.
Event two.
Starts tomorrow.
Publish.
View live, okay, we've got events, events two. And pagination is working.
First, previous, yes.
Now the pivot page needs some improvements.
And there will be some aesthetic changes we'll need to make, but I'm not gonna go to, I think the only thing is it's got this weird wrapper here.
March and start, or it doesn't even need anything.
That was it.
All right.
So events is done. We're gonna get a shared code in events.
Search is using paginated items and...
Okay, not the template, so here we go.
(keyboard clacking)
Paginated search results.
And...
I don't know if we need the query string.
I'll look at that.
Try it without there.
Not the query string, I think, because the...
I think we're gonna need the query string.
Yeah, yeah, yeah.
Okay.
So I'm dual encoding it here because it cannot allow...
I don't know if I was trying to allow or prevent...
Like SQL injection and those types of attacks.
(keyboard clacking) When I have this search query in a library view...
(keyboard clacking)
which is essentially attached to the model,
library index, page model, I get the query,
and I use it directly.
All right.
So in this search... (keyboard clacking) I think Django sanitizes this for me.
I like the model for the search or the view in this case. We're actually...
Search query. (keyboard clacking) Using the same, I think it's...
Let's add GPT if it's good.
(keyboard clacking)
There's Django sanitized values and query strings
via requests I get. Yes, Django does automatically sanitize values obtained through request get to prevent security vulnerabilities like cross-site scripting.
When you access the query string parameters via request get, Django returns in its instances of query_dx classes. This class handles escaping characters that could be potentially dangerous in HTML context. Okay, very good. I was a bit overly cautious there and for good reason, but Django, this is one reason I'm using a framework like Django is because it has these practices and collective wisdom built into it.
And it saves me from like really complex things that I'm not even aware of, that I'm barely aware of, foot cons, major security vulnerabilities. So, and it includes you, you are un-coding if you do need to manually do that.
I think this should be good then. I got the search query and pagination should work. Let's try it out.
So I'll go back to my little friendly search here and I need to fix that. I'll do that, test.
Test nothing and that's probably good there.
All right, advance pagination should be 10.
The search pagination should be one for a quick test. Viewed. Oh, so now you can have a pagination helper here.
I don't know if this is explicitly else is necessary. If there aren't any results, I think it's gonna be none. I think this will return any, okay. But let me see, what am I doing here? Query add hit, okay.
I suppose I should record the query in any case.
Even though, oh no, I see, I see.
I'll return the search results in any case.
(keyboard clanking)
I don't think this is necessary.
My pagination.
I like these named variables here and we'll just do one per page for the moment.
Refresh it and our pagination is working next.
Whoa, whoa, whoa, whoa, whoa, whoa, whoa.
Yes.
(keyboard clanking)
So the Q equals test, okay. And Q equals test or query equals test. So that like got passed in, but my paginator.
And we should use the same, well, I have to use the same query.
Query string, query string key or whatever that would be called across all these apps. Okay, no problem.
Pagination.
Paginator, current query string.
Yeah.
That was the problem. That's a bug, but I don't have to fix it in one place.
So long as,
I use the same.
(keyboard clanking)
Query model has been removed to the Wagtail Contrib search promotions, please update your code using the query model from that application. Okay, I can maybe fix that while I'm in this area. So we've got queries and none, so that's correct.
Now query is test. So if I go here, page two and test. And I need refresh, page two and query equals test. So that works, page three, yes. Preserving the query string.
(keyboard clanking) Wrong button there.
Ah, come on.
I don't know what I'm doing. So the other thing in our view.
(mumbles)
I think I've tried this.
Wagtail Contrib search promotion.
That'll get one deprecated. (keyboard clanking)
One deprecation notice.
And we'll do 10 per page now. Back to our previous value. Okay, so we're getting closer.
I need to make sure the library uses this.
In its context.
Okay, it's a bit different.
It's using these facets.
Ah, shoot.
(keyboard clanking)
I see why I did that then, okay.
Because it's supposed to grab the whole query string and why didn't that work before?
Hmm.
(keyboard clanking)
In other words, it's supposed to grab everything here.
(keyboard clanking)
(keyboard clanking) I think this is what happened last time I tried to switch to this query.
(keyboard clanking) Where's the library?
(keyboard clanking) (keyboard clanking) (keyboard clanking) (keyboard clanking)
(keyboard clanking) (keyboard clanking) (keyboard clanking)
(keyboard clanking) (keyboard clanking) (keyboard clanking) (keyboard clanking)
(keyboard clanking) (keyboard clanking) (keyboard clanking) (keyboard clanking) (keyboard clanking)
(keyboard clanking) (keyboard clanking) (keyboard clanking) (keyboard clanking)
(keyboard clanking)
Interesting, that's a new change. Okay, so,
current query string is the whole thing.
I need to revert this change.
I've tried it, causes an error.
Or did it? Ah, shoot, maybe not.
All right.
Did I not save it? No, I didn't save.
Yeah, that one line change breaks things, dang it. All right, let me get my T and we'll continue. We're getting close, but I've encountered a bit of a snag.
(keyboard clanking) All right, cool. So the search query is here. I'll just refresh the page as we got it there in the query string. Now, if I introduce pagination, it should carry over this entire query string.
Everything after the question mark should be good to go.
Ah, darn, I didn't actually want to close that. It's all right.
I'll leave it open.
So paginator HTML, I think is fine. It's the current query string, everything after the ampersand.
Now my search HTML includes the paginator with the query string. Ah, okay.
Here's the rub. Search query is only the key word.
So in order to do this,
I can get the current query string out of, while in the template or from the server.
Let's see.
I think it just requires get dictionary or something like that. (keyboard clacking)
So I have to have the context processor enabled, which we do.
Get URL and code. All right, let's try that and see if this works. How do you, scrolling.
And that must make it safer.
So here I need a URL and code it. Can we just use that? Let's try it out.
Thank you, Chad GPT for making me a stronger developer. I need to get this,
pagination to have fewer results model.
So where are we? Where are we here? The library.
I'm not working with that currently.
Search views pagination by number of items one. Really quick and then we'll refresh.
Refresh, here we go.
Yeah.
Here's the weird thing that starts to happen. It starts to compound.
Arr, matey.
(keyboard clacking) Something just look how I did this in the media library.
Yeah, so what did I do in the library? (keyboard clacking) (chuckles)
(keyboard clacking)
(keyboard clacking) Or more specifically, what should
I have a function here and basically I'm passing in a context variable into the view, into the search view and it's the wrong thing. The search query is the wrong thing for what I'm trying to achieve.
It's the right thing here,
but the wrong thing here.
I think just an F string should do it.
(keyboard clacking)
(keyboard clacking) (keyboard clacking)
This is hard to think about. Sorry, I'm a bit slow, but.
Ah, yeah, I won't work there. Oh, great.
Man, getting tired. Okay, so the search query is used in the search bar. So that we can't really change.
No problem.
All I need to do
(keyboard clacking) So I just do that search query string, I suppose.
(keyboard clacking)
Yeah, thank you.
GPT for making me a stronger developer.
Gosh.
Search query test.
And it's not compounding anymore, good.
Last, good. All right, crisis averted. I don't know if that's been a strong wording, but yeah. I'm gonna try to get this done.
Get this done.
(keyboard clacking) (keyboard clacking)
All right, the other thing. So we're using the paginated search results and introduce a new context variable here, but that's okay.
Yeah, and this is also using
common pagination. I like it, I like it.
Oh, wait, I say never. I always want it to prompt me there
or not let me do that action.
I have to explicitly stage my changes.
There we go.
All right, so I think there was only like one more.
So we get paginated items there, get paginated items in our library.
Library is working good.
Magazine, get paginated items in the magazine. Paginate our archive issues and paginated.
That's the only place we're using them, I suppose.
So in our template, then let's come to the corresponding template in the magazine.
Let's see, library I'm closing.
Views and search I'm closing. Let's go back to these search results. Here we go.
Magazine, what are we looking at?
Deep Archive Index Page.
Deep Archive Index Page, and we should have a paginator down here.
Here it is.
So, what do you know? Let's actually grab our library index page template and grab the paginator.
Tag.
And for this, we don't need to, we don't need that. We don't need to, we don't need that.
Or any of this.
And I'll create a couple of archive issues.
Then we'll go back to the Deep Archive page.
Refresh, we've got two issues.
And pagination setting was here. (clicking)
I just like these named variables.
Self-documenting, it's our item page is fine.
Refresh now. Okay, so now we're doing our pagination. So that's cool.
Paginated archival issues. Ah, see I'm returning the page here. That's not correct. Then in the template I need to adjust it. So, we're gonna
grab the page of items. (clicking)
And then passing the paginator there.
Refreshing that and looking good.
Yeah, it's got a little trailing ampersand. It's okay.
It's a small detail, but this is a big improvement overall.
And the main issue is that we should probably display.
I don't know. Another challenge we're gonna face, I just realized,
is that our pagination we're using row, oh no, no, this is just the paginator. This is just a paginator.
Our layout uses rows and columns. I'm just not thinking correctly.
We define, so if we wanted to display eight items at that time, then I can configure that here and get the paginated items out. It's never mind. It's beside the point because we do tweak the layout here, the column and row count. And we need to be able to do that and sit you in the right context. All right, so there we go. I'm just for page 12. See, I think in fact 12 is the right number here for some reason because I think we have four columns as well.
Three rows, so yeah, good thing I thought of that.
So we're using our, in fact, it's a bit redundant to do this, I think I can just, I don't need this placeholder variable really.
And just do this.
Yeah.
And look at all that code we removed. Multiple places where we just had inconsistencies, potential bugs creeping up.
Maybe security issues, basically the more you do the same thing over and over,
the more times you have a chance to do it for failure. But if you have everything consolidated in one place, then you can just scrutinize that one particular place. And every time you pass over that, it gets better, I think, in some way.
So I think we're in good shape here.
If I look at our other places where we're using pagination in the magazine, you know we've got paginated items and...
If I go back to my original search.
I should only really be...
using paginator in one place. So I've got my tests.
So I do a case into the search here.
This is to assert that they are equal.
(clicking)
And then here.
Here we go.
(clicking) Magazine index page, okay.
(clicking)
So this is no longer necessary.
And I think I can just get rid of all this.
Get paginated items here.
(clicking)
(clicking)
(clicking)
Items.
Items for page, page number.
(clicking)
So if I come over here now and we go to the magazine page.
And I need to fix the template then.
Magazine index page.
And we're trying to iterate. We're saying for...
Issue and archive issues page.
There we go, recent archives.
So what I'll do is add a child page. And this needs to be just a little bit older.
From, oh let's just put it a few years ago.
Or last year's one, publish.
So now if I go, we need archive issue too.
So I can test the pagination.
And we'll set that to 2821.
But it doesn't really matter.
Now we can view live.
All right, so now we notice nothing is showing up.
So I'm just gonna find what's breaking down. So first...
See all this pagination can go away except...
I'll have to change this page number.
That's the tricky part here.
Page is one.
And then I can use my...
Because we're not using pagination up here.
I don't think we need the current query string. Archive issues. Alright, so now we're just doing a little bit of debugging here.
I'll stop the server here and find out maybe my query is wrong, my query set is empty.
Let's see if we're getting anything back. Archive issues are just the old issues.
So basically, if I refresh now, we should hit this breakpoint and see we've got an empty query set. Okay, okay. So that's strange. I'll refresh my, continue. Edit. This page publication date. It should have been, oh, I know it happened.
I didn't pick a date, so it actually didn't persist them. Alrighty then. Yeah.
Actually, it's a two-part thing. I can't just set the year. Alright, alright.
Now we can view that live. Now we have archive issues. Very good. Continue.
Yes, yeah, this working as correct as expected. And let's just say one per page, see if we get the nice pagination widget.
Here we move my breakpoint. It's not so much needed now.
Yeah, there's our paginator. Okay, page one and page two.
So we have the first page one and we have the ampersand, but I'm not going to fuss over that too much.
Yes.
No, no, not that. Yeah, removing all this excessive code, unnecessary typecasting and just inefficient,
but it's more a matter of inconsistent duplicate copy paste with random variations.
Wait, did this work? Yeah, because I changed it in both places, apparently. Right here, sir. Where is it? Page.
Oh, we're not using the query. I'm so tired right now. Just going to go for it. Hopefully I'm not introducing any bugs here. Yeah, just change it to page and so archive issues page. Yeah, that's what I was checking and it works. Page one, page two, last, previous, next, first. Yeah.
Use common pagination. There we are.
Some lint. Yeah, removing this paginator. I should only import this in one place in the project. If it's in any other files, then it's another place I need to clean up.
So searching for paginator, remove this full paginator.
So yeah, we'll clean that up. Yeah, that's my to-do. That's what I'm actually doing now. Cool.
Only one other place. Looks like memorials. So let's finish this. Memorials, templates, memorial index page.
So we're going to iterate over each memorial in the query set page and pagination down here is going to use the shared pagination.
Where? Get it from here. And the items are memorials. And then the memorials just needs this.
Oh, that's redundant.
What memorials and their community about us.
Okay. So I have to specify the memorial meeting in order for it to work.
Or make that safe. Oh yeah, I'll just make it safe. I think in most cases we're going to have a memorial meeting, but it's not a required field.
I see.
I have a title and then this memorial meeting. It's a bit tricky.
Not the most beautiful. All right. That should allow us to view the memorials now.
Community memorials. Okay. So we've got two memorials and we have an empty paginator, but hey, we're getting somewhere. All right. So we've got this. The paginator is not working. Memorial one renders. And since I didn't associate a meeting with it, it didn't work. There's some template cleanup we need to do. But overall right now my task is just pagination. Memorial index page. There was a paginator. I didn't quite get that.
What happened?
I don't know how this will work.
Hmm.
No, that's cool. It should still work.
Filter separately than we paginate.
But
my stone debug mode.
No, apparently not.
Cause I didn't hit my break point there.
Okay. Memorial. So filtered memorials is a query set. That's expected.
And the memorials is paginated with a lighted page range.
I think this is because it's not hitting the pagination limit.
There it is. All right. So then the other thing is I just don't need to wrap this. We had an empty card. I don't need to wrap that in the empty card or list group item, whatever.
That's fine. And whether or not we went at center is another thing, but the parent template determines the layout while the paginator is just responsible for the widget itself and the widget can fit into the constraints of the template. We can review those for consistency with the editor.
Yeah, I think we're good to go.
But for example, if we don't want it justified center, I can just
do this and we're good to go. I think it looks a bit better centered though.
So we'll have some remaining inconsistencies, but overall we've moved towards much more cohesive, consistent, and perhaps reduce bug code.
Fixed a couple of bugs along the way.
I think we're ready to roll. Publish that. Open a pull request.
And what we'll do is check the issues that we're closing in our backlog.
Current focus, unified pagination, search pagination. So we're going to close in 825 and 934.
About 2 hours.
Create that pull request. Time tracking for open source work. Thanks to my current employer, Wonderdog, we have a open source benefit where they'll pay us for contributions to open source projects. It's a nice benefit up to a certain amount per month. So I appreciate Wonderdog for that opportunity to support this open source work for Western friend.
Actually we went through a lot more templates than I thought, but our whole project now is using a unified paginator. We've only got tests now and pagination helper.
So that's the only place we can port the Django paginator now. The unified helper and then specific tests where we need to basically compare the pagination result with the expectation.
On that note, let's run these tests real quick.
Actually they're probably already running here. If I go to my pull request, yeah they are. There they are.
Sometimes it's a bit faster to run the tests here than in CI. One thing we should notice is the lack of the deprecation notice, or not deprecation, but the queries that sorting, warning from the previous test that I sort of fixed. Uh oh, we've got some errors though now. Our results are in over here, but it's more convenient here, but essentially, search no query.
I did break some stuff, darn it. Alright, well I'm going to take a quick break in and we'll fix these tests. Be right back.
Okay, a few tests. Let's take a look.
Test search no query. Well if I reverse for the search, we should get a response code with zero results. Yeah. It's getting five results. Okay. That is something I noticed earlier. So it's going to basically return the whole database. And I see why, I see how I introduced that change. I remember now I actually thought it would return none. But if there were no queries, but it returns everything.
Is that how it's designed to work? Okay. Now I remember, now I learned TIL. It's a search.
View. Okay. So if there is no query.
Alright. What was the specific change? If I look here.
I think it was just none. But let me, let me see.
Okay. Okay. Drop it actually none. Right. So I just basically need this.
Right. So it's a, if we don't get a query, it returns everything. It's a greedy search instead of a conservative search. Wow. Good to know. So we can run this.
Test for just the search.
Those are good. All right. So what else did we get? So just my tests. I have to kind of fix that. Okay.
There's probably some redundancy here in my tests.
617.
Okay. Okay. Okay. Okay. Okay.
Okay. Okay.
Okay. Okay.
Thanks. Okay. Okay. I hope I got them all too bit clunky this scrolling. It's not smooth and I'm thinking I missed some. That one. That one.
That'll join them all again. No, I lost track, but yeah.
1 Fry Alrght
failure. 1 equals 2. So perhaps I left the memorials pagination. Yeah. To the wrong page number. Now it's easy mistake. I think 10 is probably what we're after there. Because we're not displaying them in a grid. Alright. 1.0 equals 8. Okay. Now
here. So I want to fix. I think a lot of these are duplicates.
Alright. So we're just going to run the magazine tests next time.
Expected archive issues per page.
8 is not equal to 2.
Mm hmm. Here's the problem there.
A page.
Gosh, there's a lot of these errors.
Very cool.
Okay, so our events page is returning extra results, expected number per page, I guess.
So let's see if the items per page is correct.
We expect 10.
We're getting only 3.
We expected more. All right, so we've entered some models. If I go to the paginated items, use it to target me. I keep doing that.
Down here, we have 10 per page. Okay, so this is strange. [silence] Could be the category. Let's see.
Test, get context pagination.
Here we're not...
Ah, yeah, it has a default filter.
Not sure.
Now these are Western events.
Dang it.
[silence]
I'm wondering if this test is just incorrect.
[silence]
What I'm going to do is manually test this.
[silence]
And if I set this pagination in the events model to 1 per page.
[silence]
We do, in fact, get the correct pagination. I think the test case is wrong.
At this point, I'm kind of just more inclined to delete it.
[silence]
It's sort of testing the Django paginator directly anyway, which I think is already pretty well tested.
Granted, I'm tired, so I'm not thinking.
Oops, very well.
But I'll run these tests one more time.
I think we're safe to push these changes now, though.
Or to commit the changes, fixed tests.
[silence] It could be that the behavior of the paginator in my context. [silence] The template context changed and invalidated that test.
[silence]
But I already have a unit test on the pagination widget.
And the common pagination code is under test as well, I believe. Let's double check that.
[silence] Actually, yeah, tests. Yeah.
So we have tests that it behaves correctly.
And I guess another good thing is having this pagination spread across the app in so many places, behaving inconsistently meant my tests were a bit more brittle.
But now I've got the code and everything centralized. So everything we're good to go.
Fixed tests, commit.
Synchronized changes.
So yeah, this has been actually a pretty good session.
[silence] Pretty lengthy sessions almost. Well, it's a little after 1.30 in the morning.
[silence] This has been another live code hangout. We've been working on the Western Friend project.
[silence] If you'd like to check the changes we made today, working on Django pagination, it's pull request number 952.
[silence]
We removed more lines than we added, but we did need to move some things around and modify some tests. So we've got some green lines here.
Primarily, we've been focusing on removing duplicate pagination logic that was spread out throughout our application and consolidating that to a single unified helper function.
It takes arguments from the context. We have different pagination parameters depending on which items we're paginating. Sometimes we want eight per page, sometimes ten.
So essentially, it's just-- and then the HTML was also moved to a shared template. So we had several inconsistencies here, either using different parameters or button classes.
Sometimes layout was different.
So all of that's changed and just modified our tests to deal with the new pagination context we had shifted.
We were no longer passing the page directly to the templates. We were passing the paginator to the templates so that it could be passed into the paginator markup.
And we moved to, I believe, a flaky test. I've already got this pagination test more or less covered in the pagination app here.
And you can see an example here. We're removing all these lines of code down to a single unified paginator. So that's really good.
Same thing, removing a lot of pagination logic.
Could have been buggy or have different behavior than other places and even doing unnecessary steps. And we have just one shared unified function.
So that's it. It's pretty much the same thing over and over. Here's the 50 lines of pagination template if you're interested in having pagination on your own site and might be using the bootstrap 5 framework. Then you can just copy and paste ours.
If you'd like to check out this project, you can stop by github.com slash westernfriend. And we're in the WF website project, which I might rename soon.
There are a lot of issues here that are labeled good first issues. They're usually small items that you can kind of just try out and then get a feel for how our project works. And perhaps if you're wanting to learn Python and Django and get some open source contributions under your belt, these are a great place to start. Actually, this I just did as well.
Close as 949.
Let me double check that I was able to do that.
Do a case sensitive search for query. There it is.
No, that's not it.
Darn it. Let me just see if I can do that here. Search.
Promotions.
I think I did that.
Where is it?
I have an hour time of seeing it.
Something I collapsed maybe. Let me just look in our editor.
Close the editor.
Sorry.
Oh, here it is. Okay, let's just take it.
Real quick.
Yeah, I did try it and I gave it this error.
(scissors snipping)
All right, so I did try, didn't work, all on the side myself.
Wrong button.
All right, a bit of an aside.
Nonetheless, that means I can't. I need to remove that from the conversation.
And I can merge this change set.
Okay, this has been another open source live code hangout. Thanks for stopping by.
On step stair. That was nice chatting.
It's always nice to have somebody today. Hang out and thanks for the subscribe.
Okay, I hope you're doing well and have a great day.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment