It depends if you need to know if a sample is from the train or validation data set.
If it doesn’t matter, the most elegant solution might be to use a ConcatDataset.
Using this approach you can just concatenate both data sets into a new one. The DataLoader might take care of shuffling if needed.
Here is a small example:
class MyData(Dataset):
    def __init__(self):
        self.data = torch.randn(100, 1)
        self.target = torch.Tensor(100).uniform_(0, 10).long()
    
    def __getitem__(self, index):
        x = self.data[index]
        y = self.data[index]
        return x, y

    def __len__(self):
        return len(self.data)

train_dataset = MyData()
val_dataset = MyData()
train_val_dataset = ConcatDataset([train_dataset, val_dataset])

for batch_idx, (data, target) in enumerate(train_val_dataset):
    print(batch_idx)

However, if you need to call both data sets separately, you could zip both sets in the for loop.
One drawback of this approach (at least in this simple form) is that both datasets must have the same length, since the loop is iterating both sets in one loop.
Here is a small modification to the aforementioned code:
train_loader = DataLoader(train_dataset)
val_loader = DataLoader(val_dataset)

for batch_idx, (train_batch, val_batch) in enumerate(zip(train_dataset, val_dataset)):
    print(batch_idx)
    data, target = train_batch[0], train_batch[1]
    val, target_val = val_batch[0], val_batch[1]

I would prefer the first approach, if it fits your needs