Key generating program in Python
The reason that you are getting so many more entries is because of this list comprehension:

 students_plus_codes = [x + str(" - " + y) for y in students for x in code_list]


It's a nested for loop. If we expand it we can see what is happening:

students_plus_codes = []
for y in students:  # students has 24 items
    for x in code_list:  # code_list has 24 items
        students_plus_codes.append(x + str(" - " + y))


So for every iteration of students you do 24 iterations of code_list. 

Fortunately, python has a builtin function called zip that will merge lists for us. So we can replace the nested list comprehension with this line:

students_plus_codes = list(zip(students, code_list))


Which results in a list of tuples:

[('Aljoša', '256D2B'), ('Blažka', 'OEGJL9'), ('Nana', 'GB1PJL'), ('Kaja', 'F0P0F2'), 
 ('Alja', '62KU94'), ... ('Matic', 'E7CJIP'), ('Marija', '1D2UCL'), ('Žiga T.', '6X1DD5')]


Generating the codes:

First, I would replace for i in range(24): with for i in range(len(students)): as this allows you to change the number of students without having to change other aspects of your code. In this instance 24 is a magic number that could cause issues down the line.

You could even create a function that generates each code, then you can use an easy to read list comprehension.

# &lt;=python3.5
def generate_code(n, characters):
    return ''.join([random.choice(characters) for _ in range(n)]) 

# &gt;=python3.6
def create_code(n, characters):
    return ''.join(random.choices(characters, k=n))


Printing the codes:

It isn't ideal to join the names and codes as a single string as this makes it hard to use them separately later. For this reason, I used a list of tuples to match them as pairs. To print them the for loop has two variables, student and code that takes advantage of unpacking and then prints them using the format function.

for student, code in students_plus_codes:
    print('{} - {}'.format(code, student))




Altogether:

import random
import string


def create_code(n, characters):
    return ''.join(random.choices(characters, k=n))


students = ["Aljoša", "Blažka", "Nana", "Kaja", "Alja", "Tjaša", "Ana",
           "Gal", "Danijela", "Alma", "Neja", "Žiga K.", "Patricija", "Aja",
           "Kristjan",  "Urban",  "Janja", "Lea", "Žana", "Aljaž", "Tilen",
           "Matic", "Marija", "Žiga T."]

# It generates the code and puts it in a list
key_size = 6
chars = string.ascii_uppercase + string.digits
code_list = [create_code(key_size, chars) for _ in range(len(students))]

# Combines the two lists (students and codes) into a list of tuples
students_plus_codes = list(zip(students, code_list))

for student, code in students_plus_codes:
    print('{} - {}'.format(code, student))