Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ please scroll down to [Windows non-WSL Setup](#windows-non-wsl-setup).
10. Verify the following pages load:
* http://127.0.0.1:8000/
* http://127.0.0.1:8000/p/
* http://127.0.0.1:8000/p/term-writer-recognize-race-available-5291/
* http://127.0.0.1:8000/p/welcome-to-our-newsletter/
11. Log into the admin ([link](http://127.0.0.1:8000/admin/)) with your superuser.
12. Verify the following pages load:
* http://127.0.0.1:8000/post/create/
Expand Down Expand Up @@ -183,7 +183,7 @@ Proceed to [Lab 1](docs/lab1.md).
10. Verify the following pages load:
* http://127.0.0.1:8000/
* http://127.0.0.1:8000/p/
* http://127.0.0.1:8000/p/term-writer-recognize-race-available-5291/
* http://127.0.0.1:8000/p/welcome-to-our-newsletter/
11. Log into the admin ([link](http://127.0.0.1:8000/admin/)) with your superuser.
12. Verify the following pages load:
* http://127.0.0.1:8000/post/create/
Expand Down
20 changes: 9 additions & 11 deletions docs/lab1.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ git checkout lab-1.1

### Report

The detail view for the post "Term writer recognize race available." is broken.
The detail view for the post "Welcome to Our Newsletter" is broken.

To reproduce:
1. Browse to the [posts page](http://127.0.0.1:8000/p/).
2. Click on "Read" for the post with the title "Term writer recognize race available."
2. Click on "Read" for the post with the title "Welcome to Our Newsletter"
3. "It doesn't work!"

### Facts
Expand All @@ -28,7 +28,7 @@ Let's consider what we know:
QuerySet does not contain a Post matching the filters.
- The line that causes the error is on line 80:``post = posts.get(title=lookup)``
- We know the post exists, we can find it in the
[admin](http://127.0.0.1:8000/admin/newsletter/post/?q=Term+writer+recognize+race+available.)
[admin](http://127.0.0.1:8000/admin/newsletter/post/?q=Welcome+to+Our+Newsletter)
- This impacts more than just the post in the report. The detail
view is broken for all posts.

Expand Down Expand Up @@ -63,7 +63,7 @@ printed the value in the view ``print(lookup)``. From there, we would have had t
recognize that ``lookup`` wasn't the actual title. This may have required us to compare
the ``lookup`` value to instance's values in the admin. We can view these values by
clicking on the instance from our
[admin search from earlier](http://127.0.0.1:8000/admin/newsletter/post/?q=Term+writer+recognize+race+available.).
[admin search from earlier](http://127.0.0.1:8000/admin/newsletter/post/?q=Welcome+to+Our+Newsletter).

</details>

Expand Down Expand Up @@ -230,11 +230,9 @@ order of most recent to oldest, but they appear jumbled.

To reproduce:
1. Browse to the [list posts](http://127.0.0.1:8000/p/) view.
2. The dates are ordered from most recent to oldest, but posts such as
"Campaign expect page information wrong more." and "Example
become begin wish painting economic."
appear out of order in comparison to "Skill fight girl north
production thus a." and "New star by chair environmental family Congress degree."
2. The dates are ordered from most recent to oldest, but the post
"Getting Started with Python"
appears out of order in comparison to "Welcome to Our Newsletter"
3. "It doesn't work!"

### Facts
Expand Down Expand Up @@ -290,8 +288,8 @@ This is root problem since the collection of posts are actually ordered based on
The posts are being ordered correctly, ``publish_at`` first, falling back to
``created`` when unset. Therefore the template must be rendering incorrectly.
This can be confirmed by comparing the fields of the posts that render
[correctly](http://127.0.0.1:8000/admin/newsletter/post/?slug=hear-after-debate-thousand-medical-give-85694)
and [incorrectly](http://127.0.0.1:8000/admin/newsletter/post/?slug=add-they-debate-guess-leg-21809).
[correctly](http://127.0.0.1:8000/admin/newsletter/post/?slug=getting-started-with-python)
and [incorrectly](http://127.0.0.1:8000/admin/newsletter/post/?slug=welcome-to-our-newsletter).
From the admin, we can see the correctly rendering Post does not have a value
for ``publish_at``, while the incorrectly rendering Post does have a value
for ``publish_at``. We can see that the ``publish_at`` value is significantly
Expand Down
4 changes: 2 additions & 2 deletions docs/lab2.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ The site seems to be running slower lately. Please make the site fast again!

To reproduce:
1. Browse to the [posts page](http://127.0.0.1:8000/p/).
2. Browse to a [post's page](http://127.0.0.1:8000/p/term-writer-recognize-race-available-5291/).
2. Browse to a [post's page](http://127.0.0.1:8000/p/welcome-to-our-newsletter/).
3. Browse to the [posts admin page](http://127.0.0.1:8000/admin/newsletter/post/).
4. Why are these slow?

Expand Down Expand Up @@ -70,7 +70,7 @@ that ``Post.categories`` is a ``ManyToManyField``, we'll need to use ``.prefetch
Since the categories need to be specifically ordered, you'll need to use a
[``Prefetch``](https://docs.djangoproject.com/en/stable/ref/models/querysets/#django.db.models.Prefetch) instance rather than just a string.

Moving onto an individual [post page](http://127.0.0.1:8000/p/term-writer-recognize-race-available-5291/),
Moving onto an individual [post page](http://127.0.0.1:8000/p/welcome-to-our-newsletter/),
the SQL panel only shows 1 query. Clicking into that panel, we'll see some really low value,
like 5ms. This in pretty much every definition is fast. However, let's trust the reporter
that this is actually slow. The next step is to understand what about this query is
Expand Down
8 changes: 5 additions & 3 deletions project/data/author.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
from django.contrib.auth.models import User

from project.data.factories import SuperUserFactory


def generate_data() -> User:
if user := User.objects.filter(is_superuser=True).order_by("date_joined").first():
return user

user, _ = User.objects.get_or_create(
return SuperUserFactory(
username="default_user",
defaults={"first_name": "Django", "last_name": "Pythonista"},
first_name="Django",
last_name="Pythonista",
)
return user
17 changes: 5 additions & 12 deletions project/data/category.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from dataclasses import dataclass

from project.data.factories import CategoryFactory
from project.newsletter.models import Category


Expand All @@ -12,18 +13,10 @@ class CategoryData:


def generate_data() -> CategoryData:
social, _ = Category.objects.update_or_create(
slug="social", defaults={"title": "Social"}
)
technical, _ = Category.objects.update_or_create(
slug="technical", defaults={"title": "Technical"}
)
career, _ = Category.objects.update_or_create(
slug="career", defaults={"title": "Career"}
)
family, _ = Category.objects.update_or_create(
slug="family", defaults={"title": "Family"}
)
social = CategoryFactory(slug="social", title="Social")
technical = CategoryFactory(slug="technical", title="Technical")
career = CategoryFactory(slug="career", title="Career")
family = CategoryFactory(slug="family", title="Family")
return CategoryData(
career=career,
family=family,
Expand Down
141 changes: 141 additions & 0 deletions project/data/factories.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
from datetime import UTC, timedelta

import factory
from django.contrib.auth.models import User
from django.utils import timezone
from faker import Faker
from faker.utils.text import slugify
from mdgen import MarkdownPostProvider
from mdgen.core import MarkdownImageGenerator

from project.newsletter.models import (
Category,
Post,
Subscription,
SubscriptionNotification,
)

fake = Faker()
fake.add_provider(MarkdownPostProvider)
Faker.seed(2022)
image_generator = MarkdownImageGenerator()

DATA_END_DATE = timezone.now().replace(
hour=0, minute=0, second=0, microsecond=0
) - timedelta(days=1)
DATA_START_DATE = DATA_END_DATE - timedelta(days=365 * 2)


def _header(level=1):
lead = "#" * level
return lead + fake.sentence()


def _short_photo_update():
return "\n\n".join(
[
_header(level=1),
fake.paragraph(),
image_generator.new_image(
fake.sentence(),
f"https://picsum.photos/{fake.pyint(200, 500)}",
fake.text(),
),
fake.paragraph(),
]
)


class UserFactory(factory.django.DjangoModelFactory):
class Meta:
model = User

first_name = factory.Faker("first_name")
last_name = factory.Faker("last_name")
username = factory.LazyAttribute(
lambda o: f"{o.first_name}.{o.last_name}.{fake.pyint(max_value=999)}"
)
email = factory.LazyAttribute(lambda o: f"{o.username}@example.com")
date_joined = factory.LazyFunction(
lambda: fake.date_time_between_dates(
datetime_start=DATA_START_DATE,
datetime_end=DATA_END_DATE,
tzinfo=UTC,
)
)


class SuperUserFactory(UserFactory):
is_superuser = True
is_staff = True


class CategoryFactory(factory.django.DjangoModelFactory):
class Meta:
model = Category
django_get_or_create = ("slug",)

title = factory.Faker("word")
slug = factory.LazyAttribute(lambda o: slugify(o.title))


class PostFactory(factory.django.DjangoModelFactory):
class Meta:
model = Post

title = factory.Faker("sentence")
slug = factory.LazyAttribute(
lambda o: slugify(o.title) + f"-{fake.pyint(10, 99999)}"
)
author = factory.SubFactory(UserFactory)
content = factory.LazyFunction(lambda: fake.post("medium"))
summary = factory.Faker("paragraph")
is_public = True
is_published = True
publish_at = factory.LazyFunction(
lambda: fake.date_time_between_dates(
datetime_start=DATA_START_DATE,
datetime_end=DATA_END_DATE,
tzinfo=UTC,
)
)
created = factory.LazyAttribute(
lambda o: o.publish_at - timedelta(days=fake.pyint(1, 30))
)

@factory.post_generation
def categories(self, create, extracted, **kwargs):
if not create:
return
if extracted:
for category in extracted:
self.categories.add(category)


class ImagePostFactory(PostFactory):
content = factory.LazyFunction(_short_photo_update)


class SubscriptionFactory(factory.django.DjangoModelFactory):
class Meta:
model = Subscription

user = factory.SubFactory(UserFactory)

@factory.post_generation
def categories(self, create, extracted, **kwargs):
if not create:
return
if extracted:
for category in extracted:
self.categories.add(category)


class SubscriptionNotificationFactory(factory.django.DjangoModelFactory):
class Meta:
model = SubscriptionNotification

subscription = factory.SubFactory(SubscriptionFactory)
post = factory.SubFactory(PostFactory)
sent = None
read = None
Loading