We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
There's a race when creating the same content in multiple processes
`Task 90df818f-3645-4b7c-8aaa-fae400a10ae0 failed (duplicate key value violates unique constraint "file_filecontent_relative_path_digest__pu_b4bae2c2_uniq"
DETAIL:  Key (relative_path, digest, _pulp_domain_id)=(B, df7e70e5021544f4834bbee64a9e3789febc4be81470df629cad6ddb03320a5c, be9b7087-f318-48ef-81ce-f3141524c659) already exists.
)`

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pulpcore/app/serializers/content.py`
Content:
```
1 from gettext import gettext as _
2 
3 from django.db import transaction
4 from rest_framework import serializers
5 from rest_framework.validators import UniqueValidator
6 
7 from pulpcore.app import models
8 from pulpcore.app.serializers import base, fields
9 from pulpcore.app.util import get_domain
10 
11 
12 class BaseContentSerializer(base.ModelSerializer):
13     pulp_href = base.DetailIdentityField(view_name_pattern=r"contents(-.*/.*)-detail")
14 
15     class Meta:
16         model = models.Content
17         fields = base.ModelSerializer.Meta.fields
18 
19 
20 class NoArtifactContentSerializer(BaseContentSerializer):
21     class Meta:
22         model = models.Content
23         fields = BaseContentSerializer.Meta.fields
24 
25 
26 class SingleArtifactContentSerializer(BaseContentSerializer):
27     artifact = fields.SingleContentArtifactField(
28         help_text=_("Artifact file representing the physical content"),
29     )
30 
31     relative_path = serializers.CharField(
32         help_text=_("Path where the artifact is located relative to distributions base_path"),
33         validators=[fields.relative_path_validator],
34         write_only=True,
35     )
36 
37     def __init__(self, *args, **kwargs):
38         """
39         Initializer for SingleArtifactContentSerializer
40         """
41         super().__init__(*args, **kwargs)
42 
43         # If the content model has its own database field 'relative_path',
44         # we should not mark the field write_only
45         if hasattr(self.Meta.model, "relative_path") and "relative_path" in self.fields:
46             self.fields["relative_path"].write_only = False
47 
48     @transaction.atomic
49     def create(self, validated_data):
50         """
51         Create the content and associate it with its Artifact, or retrieve the existing content.
52 
53         Args:
54             validated_data (dict): Data to save to the database
55         """
56         content = self.retrieve(validated_data)
57 
58         if content is not None:
59             content.touch()
60         else:
61             artifact = validated_data.pop("artifact")
62             if "relative_path" not in self.fields or self.fields["relative_path"].write_only:
63                 relative_path = validated_data.pop("relative_path")
64             else:
65                 relative_path = validated_data.get("relative_path")
66             content = self.Meta.model.objects.create(**validated_data)
67             models.ContentArtifact.objects.create(
68                 artifact=artifact, content=content, relative_path=relative_path
69             )
70 
71         return content
72 
73     def retrieve(self, validated_data):
74         """
75         Retrieve existing content unit if it exists, else return None.
76 
77         This method is plugin-specific and implementing it for a specific content type
78         allows for uploading already existing content units of that type.
79         """
80         return None
81 
82     class Meta:
83         model = models.Content
84         fields = BaseContentSerializer.Meta.fields + ("artifact", "relative_path")
85 
86 
87 class MultipleArtifactContentSerializer(BaseContentSerializer):
88     artifacts = fields.ContentArtifactsField(
89         help_text=_(
90             "A dict mapping relative paths inside the Content to the corresponding"
91             "Artifact URLs. E.g.: {'relative/path': "
92             "'/artifacts/1/'"
93         ),
94     )
95 
96     @transaction.atomic
97     def create(self, validated_data):
98         """
99         Create the content and associate it with all its Artifacts.
100 
101         Args:
102             validated_data (dict): Data to save to the database
103         """
104         artifacts = validated_data.pop("artifacts")
105         content = self.Meta.model.objects.create(**validated_data)
106         for relative_path, artifact in artifacts.items():
107             models.ContentArtifact.objects.create(
108                 artifact=artifact, content=content, relative_path=relative_path
109             )
110         return content
111 
112     class Meta:
113         model = models.Content
114         fields = BaseContentSerializer.Meta.fields + ("artifacts",)
115 
116 
117 class ContentChecksumSerializer(serializers.Serializer):
118     """
119     Provide a serializer with artifact checksum fields for single artifact content.
120 
121     If you use this serializer, it's recommended that you prefetch artifacts:
122 
123         Content.objects.prefetch_related("_artifacts").all()
124     """
125 
126     md5 = fields.ContentArtifactChecksumField(
127         help_text=_("The MD5 checksum if available."),
128         checksum="md5",
129     )
130 
131     sha1 = fields.ContentArtifactChecksumField(
132         help_text=_("The SHA-1 checksum if available."),
133         checksum="sha1",
134     )
135 
136     sha224 = fields.ContentArtifactChecksumField(
137         help_text=_("The SHA-224 checksum if available."),
138         checksum="sha224",
139     )
140 
141     sha256 = fields.ContentArtifactChecksumField(
142         help_text=_("The SHA-256 checksum if available."),
143         checksum="sha256",
144     )
145 
146     sha384 = fields.ContentArtifactChecksumField(
147         help_text=_("The SHA-384 checksum if available."),
148         checksum="sha384",
149     )
150 
151     sha512 = fields.ContentArtifactChecksumField(
152         help_text=_("The SHA-512 checksum if available."),
153         checksum="sha512",
154     )
155 
156     class Meta:
157         model = models.Content
158         fields = base.ModelSerializer.Meta.fields + (
159             "md5",
160             "sha1",
161             "sha224",
162             "sha256",
163             "sha384",
164             "sha512",
165         )
166 
167 
168 class ArtifactSerializer(base.ModelSerializer):
169     pulp_href = base.IdentityField(view_name="artifacts-detail")
170 
171     file = serializers.FileField(help_text=_("The stored file."), allow_empty_file=True)
172 
173     size = serializers.IntegerField(help_text=_("The size of the file in bytes."), required=False)
174 
175     md5 = serializers.CharField(
176         help_text=_("The MD5 checksum of the file if available."), required=False, allow_null=True
177     )
178 
179     sha1 = serializers.CharField(
180         help_text=_("The SHA-1 checksum of the file if available."),
181         required=False,
182         allow_null=True,
183     )
184 
185     sha224 = serializers.CharField(
186         help_text=_("The SHA-224 checksum of the file if available."),
187         required=False,
188         allow_null=True,
189     )
190 
191     sha256 = serializers.CharField(
192         help_text=_("The SHA-256 checksum of the file if available."),
193         required=False,
194         allow_null=True,
195     )
196 
197     sha384 = serializers.CharField(
198         help_text=_("The SHA-384 checksum of the file if available."),
199         required=False,
200         allow_null=True,
201     )
202 
203     sha512 = serializers.CharField(
204         help_text=_("The SHA-512 checksum of the file if available."),
205         required=False,
206         allow_null=True,
207     )
208 
209     def validate(self, data):
210         """
211         Validate file by size and by all checksums provided.
212 
213         Args:
214             data (:class:`django.http.QueryDict`): QueryDict mapping Artifact model fields to their
215                 values
216 
217         Raises:
218             :class:`rest_framework.exceptions.ValidationError`: When the expected file size or any
219                 of the checksums don't match their actual values.
220         """
221         super().validate(data)
222         if "size" in data:
223             if data["file"].size != int(data["size"]):
224                 raise serializers.ValidationError(_("The size did not match actual size of file."))
225         else:
226             data["size"] = data["file"].size
227 
228         bad_algs = []
229         for algorithm in models.Artifact.FORBIDDEN_DIGESTS:
230             if algorithm in data:
231                 bad_algs.append(algorithm)
232         if bad_algs:
233             raise serializers.ValidationError(
234                 _("Checksum algorithms {} forbidden for this Pulp instance.").format(bad_algs)
235             )
236 
237         for algorithm in reversed(models.Artifact.DIGEST_FIELDS):
238             digest = data["file"].hashers[algorithm].hexdigest()
239 
240             if algorithm in data and digest != data[algorithm]:
241                 raise serializers.ValidationError(_("The %s checksum did not match.") % algorithm)
242             else:
243                 data[algorithm] = digest
244 
245             if algorithm in models.Artifact.RELIABLE_DIGEST_FIELDS:
246                 validator = UniqueValidator(
247                     models.Artifact.objects.filter(pulp_domain=get_domain()),
248                     message=_("Artifact with {0} checksum of '{1}' already exists.").format(
249                         algorithm, digest
250                     ),
251                 )
252                 validator.instance = None
253                 validator(digest, self.fields[algorithm])
254 
255         return data
256 
257     class Meta:
258         model = models.Artifact
259         fields = base.ModelSerializer.Meta.fields + (
260             "file",
261             "size",
262             "md5",
263             "sha1",
264             "sha224",
265             "sha256",
266             "sha384",
267             "sha512",
268         )
269 
270 
271 class SigningServiceSerializer(base.ModelSerializer):
272     """
273     A serializer for the model declaring a signing service.
274     """
275 
276     pulp_href = base.IdentityField(view_name="signing-services-detail")
277     name = serializers.CharField(help_text=_("A unique name used to recognize a script."))
278     public_key = serializers.CharField(
279         help_text=_("The value of a public key used for the repository verification.")
280     )
281     pubkey_fingerprint = serializers.CharField(help_text=_("The fingerprint of the public key."))
282     script = serializers.CharField(
283         help_text=_("An absolute path to a script which is going to be used for the signing.")
284     )
285 
286     class Meta:
287         model = models.SigningService
288         fields = BaseContentSerializer.Meta.fields + (
289             "name",
290             "public_key",
291             "pubkey_fingerprint",
292             "script",
293         )
294
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pulpcore/app/serializers/content.py b/pulpcore/app/serializers/content.py
--- a/pulpcore/app/serializers/content.py
+++ b/pulpcore/app/serializers/content.py
@@ -1,6 +1,6 @@
 from gettext import gettext as _
 
-from django.db import transaction
+from django.db import transaction, IntegrityError
 from rest_framework import serializers
 from rest_framework.validators import UniqueValidator
 
@@ -45,7 +45,6 @@
         if hasattr(self.Meta.model, "relative_path") and "relative_path" in self.fields:
             self.fields["relative_path"].write_only = False
 
-    @transaction.atomic
     def create(self, validated_data):
         """
         Create the content and associate it with its Artifact, or retrieve the existing content.
@@ -63,10 +62,16 @@
                 relative_path = validated_data.pop("relative_path")
             else:
                 relative_path = validated_data.get("relative_path")
-            content = self.Meta.model.objects.create(**validated_data)
-            models.ContentArtifact.objects.create(
-                artifact=artifact, content=content, relative_path=relative_path
-            )
+            try:
+                with transaction.atomic():
+                    content = self.Meta.model.objects.create(**validated_data)
+                    models.ContentArtifact.objects.create(
+                        artifact=artifact, content=content, relative_path=relative_path
+                    )
+            except IntegrityError:
+                content = self.retrieve(validated_data)
+                if content is None:
+                    raise
 
         return content

{"golden_diff": "diff --git a/pulpcore/app/serializers/content.py b/pulpcore/app/serializers/content.py\n--- a/pulpcore/app/serializers/content.py\n+++ b/pulpcore/app/serializers/content.py\n@@ -1,6 +1,6 @@\n from gettext import gettext as _\n \n-from django.db import transaction\n+from django.db import transaction, IntegrityError\n from rest_framework import serializers\n from rest_framework.validators import UniqueValidator\n \n@@ -45,7 +45,6 @@\n         if hasattr(self.Meta.model, \"relative_path\") and \"relative_path\" in self.fields:\n             self.fields[\"relative_path\"].write_only = False\n \n-    @transaction.atomic\n     def create(self, validated_data):\n         \"\"\"\n         Create the content and associate it with its Artifact, or retrieve the existing content.\n@@ -63,10 +62,16 @@\n                 relative_path = validated_data.pop(\"relative_path\")\n             else:\n                 relative_path = validated_data.get(\"relative_path\")\n-            content = self.Meta.model.objects.create(**validated_data)\n-            models.ContentArtifact.objects.create(\n-                artifact=artifact, content=content, relative_path=relative_path\n-            )\n+            try:\n+                with transaction.atomic():\n+                    content = self.Meta.model.objects.create(**validated_data)\n+                    models.ContentArtifact.objects.create(\n+                        artifact=artifact, content=content, relative_path=relative_path\n+                    )\n+            except IntegrityError:\n+                content = self.retrieve(validated_data)\n+                if content is None:\n+                    raise\n \n         return content\n", "issue": "There's a race when creating the same content in multiple processes\n`Task 90df818f-3645-4b7c-8aaa-fae400a10ae0 failed (duplicate key value violates unique constraint \"file_filecontent_relative_path_digest__pu_b4bae2c2_uniq\"\r\nDETAIL:  Key (relative_path, digest, _pulp_domain_id)=(B, df7e70e5021544f4834bbee64a9e3789febc4be81470df629cad6ddb03320a5c, be9b7087-f318-48ef-81ce-f3141524c659) already exists.\r\n)`\n", "before_files": [{"content": "from gettext import gettext as _\n\nfrom django.db import transaction\nfrom rest_framework import serializers\nfrom rest_framework.validators import UniqueValidator\n\nfrom pulpcore.app import models\nfrom pulpcore.app.serializers import base, fields\nfrom pulpcore.app.util import get_domain\n\n\nclass BaseContentSerializer(base.ModelSerializer):\n    pulp_href = base.DetailIdentityField(view_name_pattern=r\"contents(-.*/.*)-detail\")\n\n    class Meta:\n        model = models.Content\n        fields = base.ModelSerializer.Meta.fields\n\n\nclass NoArtifactContentSerializer(BaseContentSerializer):\n    class Meta:\n        model = models.Content\n        fields = BaseContentSerializer.Meta.fields\n\n\nclass SingleArtifactContentSerializer(BaseContentSerializer):\n    artifact = fields.SingleContentArtifactField(\n        help_text=_(\"Artifact file representing the physical content\"),\n    )\n\n    relative_path = serializers.CharField(\n        help_text=_(\"Path where the artifact is located relative to distributions base_path\"),\n        validators=[fields.relative_path_validator],\n        write_only=True,\n    )\n\n    def __init__(self, *args, **kwargs):\n        \"\"\"\n        Initializer for SingleArtifactContentSerializer\n        \"\"\"\n        super().__init__(*args, **kwargs)\n\n        # If the content model has its own database field 'relative_path',\n        # we should not mark the field write_only\n        if hasattr(self.Meta.model, \"relative_path\") and \"relative_path\" in self.fields:\n            self.fields[\"relative_path\"].write_only = False\n\n    @transaction.atomic\n    def create(self, validated_data):\n        \"\"\"\n        Create the content and associate it with its Artifact, or retrieve the existing content.\n\n        Args:\n            validated_data (dict): Data to save to the database\n        \"\"\"\n        content = self.retrieve(validated_data)\n\n        if content is not None:\n            content.touch()\n        else:\n            artifact = validated_data.pop(\"artifact\")\n            if \"relative_path\" not in self.fields or self.fields[\"relative_path\"].write_only:\n                relative_path = validated_data.pop(\"relative_path\")\n            else:\n                relative_path = validated_data.get(\"relative_path\")\n            content = self.Meta.model.objects.create(**validated_data)\n            models.ContentArtifact.objects.create(\n                artifact=artifact, content=content, relative_path=relative_path\n            )\n\n        return content\n\n    def retrieve(self, validated_data):\n        \"\"\"\n        Retrieve existing content unit if it exists, else return None.\n\n        This method is plugin-specific and implementing it for a specific content type\n        allows for uploading already existing content units of that type.\n        \"\"\"\n        return None\n\n    class Meta:\n        model = models.Content\n        fields = BaseContentSerializer.Meta.fields + (\"artifact\", \"relative_path\")\n\n\nclass MultipleArtifactContentSerializer(BaseContentSerializer):\n    artifacts = fields.ContentArtifactsField(\n        help_text=_(\n            \"A dict mapping relative paths inside the Content to the corresponding\"\n            \"Artifact URLs. E.g.: {'relative/path': \"\n            \"'/artifacts/1/'\"\n        ),\n    )\n\n    @transaction.atomic\n    def create(self, validated_data):\n        \"\"\"\n        Create the content and associate it with all its Artifacts.\n\n        Args:\n            validated_data (dict): Data to save to the database\n        \"\"\"\n        artifacts = validated_data.pop(\"artifacts\")\n        content = self.Meta.model.objects.create(**validated_data)\n        for relative_path, artifact in artifacts.items():\n            models.ContentArtifact.objects.create(\n                artifact=artifact, content=content, relative_path=relative_path\n            )\n        return content\n\n    class Meta:\n        model = models.Content\n        fields = BaseContentSerializer.Meta.fields + (\"artifacts\",)\n\n\nclass ContentChecksumSerializer(serializers.Serializer):\n    \"\"\"\n    Provide a serializer with artifact checksum fields for single artifact content.\n\n    If you use this serializer, it's recommended that you prefetch artifacts:\n\n        Content.objects.prefetch_related(\"_artifacts\").all()\n    \"\"\"\n\n    md5 = fields.ContentArtifactChecksumField(\n        help_text=_(\"The MD5 checksum if available.\"),\n        checksum=\"md5\",\n    )\n\n    sha1 = fields.ContentArtifactChecksumField(\n        help_text=_(\"The SHA-1 checksum if available.\"),\n        checksum=\"sha1\",\n    )\n\n    sha224 = fields.ContentArtifactChecksumField(\n        help_text=_(\"The SHA-224 checksum if available.\"),\n        checksum=\"sha224\",\n    )\n\n    sha256 = fields.ContentArtifactChecksumField(\n        help_text=_(\"The SHA-256 checksum if available.\"),\n        checksum=\"sha256\",\n    )\n\n    sha384 = fields.ContentArtifactChecksumField(\n        help_text=_(\"The SHA-384 checksum if available.\"),\n        checksum=\"sha384\",\n    )\n\n    sha512 = fields.ContentArtifactChecksumField(\n        help_text=_(\"The SHA-512 checksum if available.\"),\n        checksum=\"sha512\",\n    )\n\n    class Meta:\n        model = models.Content\n        fields = base.ModelSerializer.Meta.fields + (\n            \"md5\",\n            \"sha1\",\n            \"sha224\",\n            \"sha256\",\n            \"sha384\",\n            \"sha512\",\n        )\n\n\nclass ArtifactSerializer(base.ModelSerializer):\n    pulp_href = base.IdentityField(view_name=\"artifacts-detail\")\n\n    file = serializers.FileField(help_text=_(\"The stored file.\"), allow_empty_file=True)\n\n    size = serializers.IntegerField(help_text=_(\"The size of the file in bytes.\"), required=False)\n\n    md5 = serializers.CharField(\n        help_text=_(\"The MD5 checksum of the file if available.\"), required=False, allow_null=True\n    )\n\n    sha1 = serializers.CharField(\n        help_text=_(\"The SHA-1 checksum of the file if available.\"),\n        required=False,\n        allow_null=True,\n    )\n\n    sha224 = serializers.CharField(\n        help_text=_(\"The SHA-224 checksum of the file if available.\"),\n        required=False,\n        allow_null=True,\n    )\n\n    sha256 = serializers.CharField(\n        help_text=_(\"The SHA-256 checksum of the file if available.\"),\n        required=False,\n        allow_null=True,\n    )\n\n    sha384 = serializers.CharField(\n        help_text=_(\"The SHA-384 checksum of the file if available.\"),\n        required=False,\n        allow_null=True,\n    )\n\n    sha512 = serializers.CharField(\n        help_text=_(\"The SHA-512 checksum of the file if available.\"),\n        required=False,\n        allow_null=True,\n    )\n\n    def validate(self, data):\n        \"\"\"\n        Validate file by size and by all checksums provided.\n\n        Args:\n            data (:class:`django.http.QueryDict`): QueryDict mapping Artifact model fields to their\n                values\n\n        Raises:\n            :class:`rest_framework.exceptions.ValidationError`: When the expected file size or any\n                of the checksums don't match their actual values.\n        \"\"\"\n        super().validate(data)\n        if \"size\" in data:\n            if data[\"file\"].size != int(data[\"size\"]):\n                raise serializers.ValidationError(_(\"The size did not match actual size of file.\"))\n        else:\n            data[\"size\"] = data[\"file\"].size\n\n        bad_algs = []\n        for algorithm in models.Artifact.FORBIDDEN_DIGESTS:\n            if algorithm in data:\n                bad_algs.append(algorithm)\n        if bad_algs:\n            raise serializers.ValidationError(\n                _(\"Checksum algorithms {} forbidden for this Pulp instance.\").format(bad_algs)\n            )\n\n        for algorithm in reversed(models.Artifact.DIGEST_FIELDS):\n            digest = data[\"file\"].hashers[algorithm].hexdigest()\n\n            if algorithm in data and digest != data[algorithm]:\n                raise serializers.ValidationError(_(\"The %s checksum did not match.\") % algorithm)\n            else:\n                data[algorithm] = digest\n\n            if algorithm in models.Artifact.RELIABLE_DIGEST_FIELDS:\n                validator = UniqueValidator(\n                    models.Artifact.objects.filter(pulp_domain=get_domain()),\n                    message=_(\"Artifact with {0} checksum of '{1}' already exists.\").format(\n                        algorithm, digest\n                    ),\n                )\n                validator.instance = None\n                validator(digest, self.fields[algorithm])\n\n        return data\n\n    class Meta:\n        model = models.Artifact\n        fields = base.ModelSerializer.Meta.fields + (\n            \"file\",\n            \"size\",\n            \"md5\",\n            \"sha1\",\n            \"sha224\",\n            \"sha256\",\n            \"sha384\",\n            \"sha512\",\n        )\n\n\nclass SigningServiceSerializer(base.ModelSerializer):\n    \"\"\"\n    A serializer for the model declaring a signing service.\n    \"\"\"\n\n    pulp_href = base.IdentityField(view_name=\"signing-services-detail\")\n    name = serializers.CharField(help_text=_(\"A unique name used to recognize a script.\"))\n    public_key = serializers.CharField(\n        help_text=_(\"The value of a public key used for the repository verification.\")\n    )\n    pubkey_fingerprint = serializers.CharField(help_text=_(\"The fingerprint of the public key.\"))\n    script = serializers.CharField(\n        help_text=_(\"An absolute path to a script which is going to be used for the signing.\")\n    )\n\n    class Meta:\n        model = models.SigningService\n        fields = BaseContentSerializer.Meta.fields + (\n            \"name\",\n            \"public_key\",\n            \"pubkey_fingerprint\",\n            \"script\",\n        )\n", "path": "pulpcore/app/serializers/content.py"}], "after_files": [{"content": "from gettext import gettext as _\n\nfrom django.db import transaction, IntegrityError\nfrom rest_framework import serializers\nfrom rest_framework.validators import UniqueValidator\n\nfrom pulpcore.app import models\nfrom pulpcore.app.serializers import base, fields\nfrom pulpcore.app.util import get_domain\n\n\nclass BaseContentSerializer(base.ModelSerializer):\n    pulp_href = base.DetailIdentityField(view_name_pattern=r\"contents(-.*/.*)-detail\")\n\n    class Meta:\n        model = models.Content\n        fields = base.ModelSerializer.Meta.fields\n\n\nclass NoArtifactContentSerializer(BaseContentSerializer):\n    class Meta:\n        model = models.Content\n        fields = BaseContentSerializer.Meta.fields\n\n\nclass SingleArtifactContentSerializer(BaseContentSerializer):\n    artifact = fields.SingleContentArtifactField(\n        help_text=_(\"Artifact file representing the physical content\"),\n    )\n\n    relative_path = serializers.CharField(\n        help_text=_(\"Path where the artifact is located relative to distributions base_path\"),\n        validators=[fields.relative_path_validator],\n        write_only=True,\n    )\n\n    def __init__(self, *args, **kwargs):\n        \"\"\"\n        Initializer for SingleArtifactContentSerializer\n        \"\"\"\n        super().__init__(*args, **kwargs)\n\n        # If the content model has its own database field 'relative_path',\n        # we should not mark the field write_only\n        if hasattr(self.Meta.model, \"relative_path\") and \"relative_path\" in self.fields:\n            self.fields[\"relative_path\"].write_only = False\n\n    def create(self, validated_data):\n        \"\"\"\n        Create the content and associate it with its Artifact, or retrieve the existing content.\n\n        Args:\n            validated_data (dict): Data to save to the database\n        \"\"\"\n        content = self.retrieve(validated_data)\n\n        if content is not None:\n            content.touch()\n        else:\n            artifact = validated_data.pop(\"artifact\")\n            if \"relative_path\" not in self.fields or self.fields[\"relative_path\"].write_only:\n                relative_path = validated_data.pop(\"relative_path\")\n            else:\n                relative_path = validated_data.get(\"relative_path\")\n            try:\n                with transaction.atomic():\n                    content = self.Meta.model.objects.create(**validated_data)\n                    models.ContentArtifact.objects.create(\n                        artifact=artifact, content=content, relative_path=relative_path\n                    )\n            except IntegrityError:\n                content = self.retrieve(validated_data)\n                if content is None:\n                    raise\n\n        return content\n\n    def retrieve(self, validated_data):\n        \"\"\"\n        Retrieve existing content unit if it exists, else return None.\n\n        This method is plugin-specific and implementing it for a specific content type\n        allows for uploading already existing content units of that type.\n        \"\"\"\n        return None\n\n    class Meta:\n        model = models.Content\n        fields = BaseContentSerializer.Meta.fields + (\"artifact\", \"relative_path\")\n\n\nclass MultipleArtifactContentSerializer(BaseContentSerializer):\n    artifacts = fields.ContentArtifactsField(\n        help_text=_(\n            \"A dict mapping relative paths inside the Content to the corresponding\"\n            \"Artifact URLs. E.g.: {'relative/path': \"\n            \"'/artifacts/1/'\"\n        ),\n    )\n\n    @transaction.atomic\n    def create(self, validated_data):\n        \"\"\"\n        Create the content and associate it with all its Artifacts.\n\n        Args:\n            validated_data (dict): Data to save to the database\n        \"\"\"\n        artifacts = validated_data.pop(\"artifacts\")\n        content = self.Meta.model.objects.create(**validated_data)\n        for relative_path, artifact in artifacts.items():\n            models.ContentArtifact.objects.create(\n                artifact=artifact, content=content, relative_path=relative_path\n            )\n        return content\n\n    class Meta:\n        model = models.Content\n        fields = BaseContentSerializer.Meta.fields + (\"artifacts\",)\n\n\nclass ContentChecksumSerializer(serializers.Serializer):\n    \"\"\"\n    Provide a serializer with artifact checksum fields for single artifact content.\n\n    If you use this serializer, it's recommended that you prefetch artifacts:\n\n        Content.objects.prefetch_related(\"_artifacts\").all()\n    \"\"\"\n\n    md5 = fields.ContentArtifactChecksumField(\n        help_text=_(\"The MD5 checksum if available.\"),\n        checksum=\"md5\",\n    )\n\n    sha1 = fields.ContentArtifactChecksumField(\n        help_text=_(\"The SHA-1 checksum if available.\"),\n        checksum=\"sha1\",\n    )\n\n    sha224 = fields.ContentArtifactChecksumField(\n        help_text=_(\"The SHA-224 checksum if available.\"),\n        checksum=\"sha224\",\n    )\n\n    sha256 = fields.ContentArtifactChecksumField(\n        help_text=_(\"The SHA-256 checksum if available.\"),\n        checksum=\"sha256\",\n    )\n\n    sha384 = fields.ContentArtifactChecksumField(\n        help_text=_(\"The SHA-384 checksum if available.\"),\n        checksum=\"sha384\",\n    )\n\n    sha512 = fields.ContentArtifactChecksumField(\n        help_text=_(\"The SHA-512 checksum if available.\"),\n        checksum=\"sha512\",\n    )\n\n    class Meta:\n        model = models.Content\n        fields = base.ModelSerializer.Meta.fields + (\n            \"md5\",\n            \"sha1\",\n            \"sha224\",\n            \"sha256\",\n            \"sha384\",\n            \"sha512\",\n        )\n\n\nclass ArtifactSerializer(base.ModelSerializer):\n    pulp_href = base.IdentityField(view_name=\"artifacts-detail\")\n\n    file = serializers.FileField(help_text=_(\"The stored file.\"), allow_empty_file=True)\n\n    size = serializers.IntegerField(help_text=_(\"The size of the file in bytes.\"), required=False)\n\n    md5 = serializers.CharField(\n        help_text=_(\"The MD5 checksum of the file if available.\"), required=False, allow_null=True\n    )\n\n    sha1 = serializers.CharField(\n        help_text=_(\"The SHA-1 checksum of the file if available.\"),\n        required=False,\n        allow_null=True,\n    )\n\n    sha224 = serializers.CharField(\n        help_text=_(\"The SHA-224 checksum of the file if available.\"),\n        required=False,\n        allow_null=True,\n    )\n\n    sha256 = serializers.CharField(\n        help_text=_(\"The SHA-256 checksum of the file if available.\"),\n        required=False,\n        allow_null=True,\n    )\n\n    sha384 = serializers.CharField(\n        help_text=_(\"The SHA-384 checksum of the file if available.\"),\n        required=False,\n        allow_null=True,\n    )\n\n    sha512 = serializers.CharField(\n        help_text=_(\"The SHA-512 checksum of the file if available.\"),\n        required=False,\n        allow_null=True,\n    )\n\n    def validate(self, data):\n        \"\"\"\n        Validate file by size and by all checksums provided.\n\n        Args:\n            data (:class:`django.http.QueryDict`): QueryDict mapping Artifact model fields to their\n                values\n\n        Raises:\n            :class:`rest_framework.exceptions.ValidationError`: When the expected file size or any\n                of the checksums don't match their actual values.\n        \"\"\"\n        super().validate(data)\n        if \"size\" in data:\n            if data[\"file\"].size != int(data[\"size\"]):\n                raise serializers.ValidationError(_(\"The size did not match actual size of file.\"))\n        else:\n            data[\"size\"] = data[\"file\"].size\n\n        bad_algs = []\n        for algorithm in models.Artifact.FORBIDDEN_DIGESTS:\n            if algorithm in data:\n                bad_algs.append(algorithm)\n        if bad_algs:\n            raise serializers.ValidationError(\n                _(\"Checksum algorithms {} forbidden for this Pulp instance.\").format(bad_algs)\n            )\n\n        for algorithm in reversed(models.Artifact.DIGEST_FIELDS):\n            digest = data[\"file\"].hashers[algorithm].hexdigest()\n\n            if algorithm in data and digest != data[algorithm]:\n                raise serializers.ValidationError(_(\"The %s checksum did not match.\") % algorithm)\n            else:\n                data[algorithm] = digest\n\n            if algorithm in models.Artifact.RELIABLE_DIGEST_FIELDS:\n                validator = UniqueValidator(\n                    models.Artifact.objects.filter(pulp_domain=get_domain()),\n                    message=_(\"Artifact with {0} checksum of '{1}' already exists.\").format(\n                        algorithm, digest\n                    ),\n                )\n                validator.instance = None\n                validator(digest, self.fields[algorithm])\n\n        return data\n\n    class Meta:\n        model = models.Artifact\n        fields = base.ModelSerializer.Meta.fields + (\n            \"file\",\n            \"size\",\n            \"md5\",\n            \"sha1\",\n            \"sha224\",\n            \"sha256\",\n            \"sha384\",\n            \"sha512\",\n        )\n\n\nclass SigningServiceSerializer(base.ModelSerializer):\n    \"\"\"\n    A serializer for the model declaring a signing service.\n    \"\"\"\n\n    pulp_href = base.IdentityField(view_name=\"signing-services-detail\")\n    name = serializers.CharField(help_text=_(\"A unique name used to recognize a script.\"))\n    public_key = serializers.CharField(\n        help_text=_(\"The value of a public key used for the repository verification.\")\n    )\n    pubkey_fingerprint = serializers.CharField(help_text=_(\"The fingerprint of the public key.\"))\n    script = serializers.CharField(\n        help_text=_(\"An absolute path to a script which is going to be used for the signing.\")\n    )\n\n    class Meta:\n        model = models.SigningService\n        fields = BaseContentSerializer.Meta.fields + (\n            \"name\",\n            \"public_key\",\n            \"pubkey_fingerprint\",\n            \"script\",\n        )\n", "path": "pulpcore/app/serializers/content.py"}]}