Repository: marshmallow-code/marshmallow-sqlalchemy

Issue:
field_for() converter for Relationships not detecting nullable=False
Hi, I had a case where I had the following (this is example code):
```python
class Book:
    ...
    author_id = Column(Integer, ForeignKey('author.id'), nullable=False)
    author = relationship('Author', lazy='selectin')
```
And when I tried to do an `author = auto_field()` here on 'author' relationship - it gave me an error.
i dug into it, and I found the following:
```python
from marshmallow_sqlalchemy.convert import default_converter

rel = Book.__mapper__.get_property('author')
rel_kwargs = {}
default_converter._add_relationship_kwargs(rel_kwargs, rel)
print(rel_kwargs)
# Output: {'allow_none': True, 'required': False}

col = Book.__mapper__.get_property('author_id').columns[0]
col_kwargs = {}
default_converter._add_column_kwargs(col_kwargs, col)
print(col_kwargs)
# Output: {'required': True}
```

This got me confused ... cause it looks like :
 - Using the ForeignKey column - it detect the `required=True` correctly
 - Using the Relationship property- it does **NOT** detect the `required=True` correctly

Discussion:

Fix (patch):
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index cfa4a91..fd30788 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -15,6 +15,9 @@ Bug fixes:
 * Fix behavior of ``include_fk = False`` in options when parent
   schema sets ``include_fk = True`` (:issue:`440`).
   Thanks :user:`uhnomoli` for reporting.
+* Fields generated from non-nullable `sqlalchemy.orm.relationship`
+  correctly set ``required=True`` and ``allow_none=False`` (:issue:`336`).
+  Thanks :user:`AbdealiLoKo` for reporting.
 
 Other changes:
 
diff --git a/src/marshmallow_sqlalchemy/convert.py b/src/marshmallow_sqlalchemy/convert.py
index 62ae6b1..427d64c 100644
--- a/src/marshmallow_sqlalchemy/convert.py
+++ b/src/marshmallow_sqlalchemy/convert.py
@@ -458,7 +458,10 @@ class ModelConverter:
         nullable = True
         for pair in prop.local_remote_pairs:
             if not pair[0].nullable:
-                if prop.uselist is True:
+                if (
+                    prop.uselist is True
+                    or self.DIRECTION_MAPPING[prop.direction.name] is False
+                ):
                     nullable = False
                 break
         kwargs.update({"allow_none": nullable, "required": not nullable})


Test changes:
diff --git a/tests/test_conversion.py b/tests/test_conversion.py
index c43fc1b..8242ab2 100644
--- a/tests/test_conversion.py
+++ b/tests/test_conversion.py
@@ -86,18 +86,36 @@ class TestModelFieldConversion:
 
     def test_many_to_many_relationship(self, models):
         student_fields = fields_for_model(models.Student, include_relationships=True)
-        assert type(student_fields["courses"]) is RelatedList
+        courses_field = student_fields["courses"]
+        assert type(courses_field) is RelatedList
+        assert courses_field.required is False
 
         course_fields = fields_for_model(models.Course, include_relationships=True)
-        assert type(course_fields["students"]) is RelatedList
+        students_field = course_fields["students"]
+        assert type(students_field) is RelatedList
+        assert students_field.required is False
 
     def test_many_to_one_relationship(self, models):
         student_fields = fields_for_model(models.Student, include_relationships=True)
-        assert type(student_fields["current_school"]) is Related
+        current_school_field = student_fields["current_school"]
+        assert type(current_school_field) is Related
+        assert current_school_field.allow_none is False
+        assert current_school_field.required is True
 
         school_fields = fields_for_model(models.School, include_relationships=True)
         assert type(school_fields["students"]) is RelatedList
 
+        teacher_fields = fields_for_model(models.Teacher, include_relationships=True)
+        current_school_field = teacher_fields["current_school"]
+        assert type(current_school_field) is Related
+        assert current_school_field.required is False
+
+    def test_many_to_many_uselist_false_relationship(self, models):
+        teacher_fields = fields_for_model(models.Teacher, include_relationships=True)
+        substitute_field = teacher_fields["substitute"]
+        assert type(substitute_field) is Related
+        assert substitute_field.required is False
+
     def test_include_fk(self, models):
         student_fields = fields_for_model(models.Student, include_fk=False)
         assert "current_school_id" not in student_fields