Repository: pydantic/pydantic

Issue:
Discriminated union does not work with aliased literal field
### Checks

* [x] I added a descriptive title to this issue
* [x] I have searched (google, github) for similar issues and couldn't find anything
* [x] I have read and followed [the docs](https://pydantic-docs.helpmanual.io/) and still think this is a bug

<!-- Sorry to sound so draconian, but every second saved replying to issues is time spend improving pydantic :-) -->

# Bug

Output of `python -c "import pydantic.utils; print(pydantic.utils.version_info())"`:
```
             pydantic version: 1.9.0
            pydantic compiled: True
                 install path: /home/ljnsn/.virtualenvs/py39/lib/python3.9/site-packages/
pydantic
               python version: 3.9.7 (default, Sep 10 2021, 14:59:43)  [GCC 11.2.0]
                     platform: Linux-5.15.23-76051523-generic-x86_64-with-glibc2.34
     optional deps. installed: ['typing-extensions']
```
It seems like the discriminator field for a discriminated union is only recognized when it is passed by its alias, even when `allow_population_by_field_name = True`. I would expect to be able to pass the discriminator field by field name, just like any other field, when that config option is set.

```py
from typing import Literal, Union

from pydantic import BaseModel, Field


class Base(BaseModel):
    class Config:
        allow_population_by_field_name = True


class Cat(Base):
    pet_type: Literal["cat"] = Field(alias="petType")
    meows: int


class Dog(Base):
    pet_type: Literal["dog"] = Field(alias="petType")
    barks: float


class Lizard(Base):
    pet_type: Literal["reptile", "lizard"] = Field(alias="petType")
    scales: bool


class Model(Base):
    pet: Union[Cat, Dog, Lizard] = Field(..., discriminator="pet_type")
    n: int


print(Dog(**{"pet_type": "dog", "barks": 3.14}))

print(Model(pet={"petType": "dog", "barks": 3.14}, n=1))

print(Model(pet={"pet_type": "dog", "barks": 3.14}, n=1))
# > pydantic.error_wrappers.ValidationError: 1 validation error for Model pet
#   Discriminator 'pet_type' is missing in value (type=value_error.discriminated_union.miss
#   ing_discriminator; discriminator_key=pet_type)

```



Comments:
I think this is a duplicate of #3846. Apologies, I started writing this yesterday evening before the other issue was created.
Spooky that we found a similar problem around the same time! 😅

If you'd like to confirm, you could try the tentative fix that I've proposed here to see if it fixes your issue too. If so then we could link both tickets to the same PR.

https://github.com/samuelcolvin/pydantic/pull/3847
I'll check this tomorrow at work, thanks!

**EDIT**:

Just tried it out and it doesn't seem to work for the example above :disappointed: 

```
---> 35 print(Model(pet={"pet_type": "dog", "barks": 3.14}, n=1))

~/src/pydantic/pydantic/main.py in __init__(__pydantic_self__, **data)
    329         values, fields_set, validation_error = validate_model(__pydantic_self__.__class__, data)
    330         if validation_error:
--> 331             raise validation_error
    332         try:
    333             object_setattr(__pydantic_self__, '__dict__', values)

ValidationError: 1 validation error for Model
pet
  Discriminator 'pet_type' is missing in value (type=value_error.discriminated_union.missing_discriminator; discriminator_key=pet_type)

```
Can confirm, just had this same issue today
Hello, we are having the same issue.
It happens not only when passing dicts like the OP did, but also if you pass model instances (See example below).
@samuelcolvin Is there any plan to fix this soon?
Thank you

```
class Cat(BaseModel):
    pet_type: Literal['cat'] = Field(alias='pet_type_alias')
    name: str

class Dog(BaseModel):
    pet_type: Literal['dog'] = Field(alias='pet_type_alias')
    name: str

class Home(BaseModel):
    pet: Annotated[Union[Dog, Cat], Field(discriminator='pet_type')]

cat = Cat(name="Mitzi", pet_type_alias='cat')
home = Home(pet=cat)

# pydantic.error_wrappers.ValidationError: 1 validation error for Home
# pet
# Discriminator 'pet_type' is missing in value (type=value_error.discriminated_union.missing_discriminator; discriminator_key=pet_type)
```
Yes, it's fixed in pydantic-core and will be fixed in V2.
It seems this is fixed in v2:
```python
from pydantic import BaseModel, Field
from typing import Union
from typing_extensions import Literal, Annotated
class Cat(BaseModel):
    pet_type: Literal['cat'] = Field(alias='pet_type_alias')
    name: str

class Dog(BaseModel):
    pet_type: Literal['dog'] = Field(alias='pet_type_alias')
    name: str

class Home(BaseModel):
    pet: Annotated[Union[Dog, Cat], Field(discriminator='pet_type')]

cat = Cat(name="Mitzi", pet_type_alias='cat')
home = Home(pet=cat)
print(home)
#> pet=Cat(pet_type='cat', name='Mitzi')
```

Patch:
diff --git a/pydantic/fields.py b/pydantic/fields.py
--- a/pydantic/fields.py
+++ b/pydantic/fields.py
@@ -1107,7 +1107,13 @@ def _validate_discriminated_union(
         assert self.discriminator_alias is not None
 
         try:
-            discriminator_value = v[self.discriminator_alias]
+            try:
+                discriminator_value = v[self.discriminator_alias]
+            except KeyError:
+                if self.model_config.allow_population_by_field_name:
+                    discriminator_value = v[self.discriminator_key]
+                else:
+                    raise
         except KeyError:
             return v, ErrorWrapper(MissingDiscriminator(discriminator_key=self.discriminator_key), loc)
         except TypeError:


Test patch:
diff --git a/tests/test_discrimated_union.py b/tests/test_discrimated_union.py
--- a/tests/test_discrimated_union.py
+++ b/tests/test_discrimated_union.py
@@ -285,6 +285,80 @@ class Top(BaseModel):
     assert Top(sub=B(literal='b')).sub.literal == 'b'
 
 
+def test_discriminated_union_model_with_alias():
+    class A(BaseModel):
+        literal: Literal['a'] = Field(alias='lit')
+
+    class B(BaseModel):
+        literal: Literal['b'] = Field(alias='lit')
+
+        class Config:
+            allow_population_by_field_name = True
+
+    class TopDisallow(BaseModel):
+        sub: Union[A, B] = Field(..., discriminator='literal', alias='s')
+
+    class TopAllow(BaseModel):
+        sub: Union[A, B] = Field(..., discriminator='literal', alias='s')
+
+        class Config:
+            allow_population_by_field_name = True
+
+    assert TopDisallow.parse_obj({'s': {'lit': 'a'}}).sub.literal == 'a'
+
+    with pytest.raises(ValidationError) as exc_info:
+        TopDisallow.parse_obj({'s': {'literal': 'b'}})
+
+    assert exc_info.value.errors() == [
+        {
+            'ctx': {'discriminator_key': 'literal'},
+            'loc': ('s',),
+            'msg': "Discriminator 'literal' is missing in value",
+            'type': 'value_error.discriminated_union.missing_discriminator',
+        },
+    ]
+
+    with pytest.raises(ValidationError) as exc_info:
+        TopDisallow.parse_obj({'s': {'literal': 'a'}})
+
+    assert exc_info.value.errors() == [
+        {
+            'ctx': {'discriminator_key': 'literal'},
+            'loc': ('s',),
+            'msg': "Discriminator 'literal' is missing in value",
+            'type': 'value_error.discriminated_union.missing_discriminator',
+        }
+    ]
+
+    with pytest.raises(ValidationError) as exc_info:
+        TopDisallow.parse_obj({'sub': {'lit': 'a'}})
+
+    assert exc_info.value.errors() == [
+        {'loc': ('s',), 'msg': 'field required', 'type': 'value_error.missing'},
+    ]
+
+    assert TopAllow.parse_obj({'s': {'lit': 'a'}}).sub.literal == 'a'
+    assert TopAllow.parse_obj({'s': {'lit': 'b'}}).sub.literal == 'b'
+    assert TopAllow.parse_obj({'s': {'literal': 'b'}}).sub.literal == 'b'
+    assert TopAllow.parse_obj({'sub': {'lit': 'a'}}).sub.literal == 'a'
+    assert TopAllow.parse_obj({'sub': {'lit': 'b'}}).sub.literal == 'b'
+    assert TopAllow.parse_obj({'sub': {'literal': 'b'}}).sub.literal == 'b'
+
+    with pytest.raises(ValidationError) as exc_info:
+        TopAllow.parse_obj({'s': {'literal': 'a'}})
+
+    assert exc_info.value.errors() == [
+        {'loc': ('s', 'A', 'lit'), 'msg': 'field required', 'type': 'value_error.missing'},
+    ]
+
+    with pytest.raises(ValidationError) as exc_info:
+        TopAllow.parse_obj({'sub': {'literal': 'a'}})
+
+    assert exc_info.value.errors() == [
+        {'loc': ('s', 'A', 'lit'), 'msg': 'field required', 'type': 'value_error.missing'},
+    ]
+
+
 def test_discriminated_union_int():
     class A(BaseModel):
         l: Literal[1]