Skip to content

GitLab

  • Menu
Projects Groups Snippets
    • Loading...
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in
  • R roomlist
  • Project information
    • Project information
    • Activity
    • Labels
    • Planning hierarchy
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 23
    • Issues 23
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 2
    • Merge requests 2
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • SRCT
  • roomlist
  • Issues
  • #49

Closed
Open
Created Oct 26, 2015 by Daniel W Bond@dbond2Developer

engaging material on the front page

A suggestion from our first usability test-- what the heck are you supposed to do on the front page after you're logged in?

The answer: we're going to show the user two things: other students on their floor, and other students in their major.

Initially, the idea was to show the newest registrants in each category, but eventually, when enough people have signed in on your floor, that list of faces isn't going to change all that much, so will get a little dull.

Instead, we'll just show randomly selected members of each group. (This is also less computationally challenging, but the user experience issue is the greater concern.)

First, we need to grab the students in question, so time to learn about django's querysets. https://docs.djangoproject.com/en/1.8/ref/models/querysets/

A queryset is a iterator that essentially allows you to write sql commands, except with python. We've seen these already a bit: for example, Student.objects.all() and User.objects.get(username='dbond2'). So far so good, though the thought process around building more complex ones of these can get a little complicated, especially if you're not familiar with database commands. But fear ye not! We'll walk through one example for this particular issue.

For the next part, some traditional python syntax: *args, or 'arguments', and **kwargs, or 'keyword arguments'.

Student.objects.all() returns every student in the database. .get(**kwargs) returns a single student or an exception..filters(**kwargs), as may make sense, returns a select number of students with the given attributes.

What if we wanted to return all students except ourselves? We can used .exclude(**kwargs), e.g. Student.objects.exclude(user__username='dbond2'). What's up with all the underscores? To refer to attributes of a different object, 'across tables', instead of dots, we use underscores on that side of the equals sign.

Put a pin in that line of thinking; we'll return to it in a moment.

To return the students with the same major as the student requesting a page in a view (in a method such as get_context_data), we can write Student.objects.filter(major=request.user.student.major). (We can refer to both user.student and student.user because the User is a one-to-one field with Student.) Depending on your preferences for clarity, you can assign request.user.student.major to a variable. In fact, you probably should, but for this explanation we'll err on the side of explicitness. Also note that it's expected you use dots on this side of the equals sign for referencing attributes.

The fun thing about querysets is that you can chain them: you can have the output of one flow directly in the output of the next. For instance, we can combine the two above examples as Student.objects.filter(major=request.user.student.major).exclude(user__username=request.user.username). For this particular example, the ordering doesn't matter in terms of ourput, but in most cases, it'll be important. (The ordering may well however matter in terms of efficiency.) We're excluding ourselves because we're trying to show the other people in your major.

The normal ordering of this queryset corresponds with the order in which the Students were entered in the database. Let's switch that up. We can use .ordered_by(**kwargs) to reorder the items in the queryset. For instance, if we did .ordered_by('user__first_name'), our Students would be ordered by their first name from A to Z. If we instead wrote .ordered_by('-user__last_name'), with the little minus sign in front, our students would be ordered by first name from Z to A. To randomize our queryset entirely, we can use .ordered_by('?').

As noted earlier, you can operate on a queryset a lot like a list (they're both iterables), so then to cut eight out of that newly randomized list, we can then add a [:8] at the end.

Our full queryset would then be Student.objects.filter(major=request.user.student.major).exclude(user__username=request.user.username).ordered_by('?')[:8].

(It should be noted, though, that .ordered_by('?') is not particulary efficient for large (many thousands+) of objects. Given querysets' properties, we could instead use random from the standard library for the last two parts: random.sample(my_qset, 8). Another not-immediately-relevant note: you can pass as many arguments as you want in to an .filter(**kwargs) or .ordered_by(**kwargs) and it will respectively filter and order accordingly. For instance, .filter(major=request.user.student.major, building=request.user.student.get_building()).)

Why are we limiting ourselves to up to eight students? If we imagine how this is going to look on the front page, it's going to largely look like it'll appear on the detail_floor.html template (lines 18-31 as the file appears at the time of writing). That puts four students on each row: maxing out at eight students gives us up to two rows of students.

How many students should we show? For the floor, perhaps 4, maybe 8. For the major, perhaps 8, maybe twelve. Far more students would thereotically share a major than share a floor; the exact number of rows depends on what looks better on the front page.

Two last notes for the frontend-- check out the <legend> tag to have text with with a nice dividing line underneath. This will show only for the logged-in students, so make sure this is in the {% if user.is_authenticated %} tag. Depending on what you think looks better, you might move the descriptive line of features so it disappears when a user is logged in, along with the 'get started' button. And depending on what you think looks prettier, remember that bootstrap has a text-center class.

A final note to implement this featuere: before now, we've only cached full pages. Re-randomizing the students displayed every single time the page is refreshed would be taxing for the database. Additionally, we absolutely need the list of students cached to be different for every student. Thankfully, Django cacheing and templating not only allows for cacheing template fragments, but saving each fragment for a different user. https://docs.djangoproject.com/en/1.8/topics/cache/#template-fragment-caching

{% cache 900 floor_students request.user.username %} [command] [time to store in cache in seconds] [name for segment in cache database] [associated object name]

Assignee
Assign to
Time tracking