Olá Edson, tranquilo?
Eu faria da seguinte maneira:
def extremidades(i:int, j:int): # Verifica se o indice está em alguma das extremidades
return i == 0 or i == altura-1 or j == 0 or j == largura-1
altura = int(input("Digite a altura do retângulo: "))
largura = int(input("Digite a largura do retângulo: "))
i = 0
while i < altura:
j = 0
while j < largura:
if extremidades(i,j): # Chama a função que criamos
print("#" ,end = "")
else:
print(" ",end = "")
j += 1
print()
i += 1
Tentei não alterar muito o seu código, mas note que agora os indices estão começando com 0, logo as condições do while foram alteradas. Foi adicionado uma estrutura condicional para verificar se os indices i e j fazem parte da extremidade do retângulo. A função extremidades(i:int, j:int) retorna um booleano, ou seja verdadeiro ou falso, nos dizendo se i está na borda superio i==0 ou se está na inferior i==altura-1, o mesmo se repete para j, verificamos se este está na extremidade a esquerda j==0 ou se está na extremidade à direita j==largura-1 caso qualquer uma dessas condições seja verdadeira é efetuado o print("#" ,end = "") caso contrario mostramos print(" ",end = "").
Se ainda não viu funções, ficaria assim sem ela:
altura = int(input("Digite a altura do retângulo: "))
largura = int(input("Digite a largura do retângulo: "))
i = 0
while i < altura:
j = 0
while j < largura:
if i == 0 or i == altura-1 or j == 0 or j == largura-1:
print("#" ,end = "")
else:
print(" ",end = "")
j += 1
print()
i += 1
Espero ter ajudado, bons estudos! ;)