Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Solution #950

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open

Solution #950

wants to merge 3 commits into from

Conversation

FursykIvan
Copy link

No description provided.

user = models.ForeignKey(to="User",
on_delete=models.CASCADE,
null=True,
blank=True,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think null and blank dont need here

db/models.py Outdated

class Order(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(to="User",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the lecture says it's better to access the settings here. (settings.AUTH_USER_MODEL) not to="User"

Copy link

@mateacademy-ai-mentor mateacademy-ai-mentor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


Thank you for your hard work on this project! 😊 While your implementation is mostly correct, there are a few critical issues that need to be addressed before we can proceed:

  1. Exception Handling: There are multiple instances where exceptions like DoesNotExist are not handled. It's important to handle these exceptions to ensure smooth operation and provide user-friendly error messages. This applies to functions like get_user, create_order, and delete_movie_session_by_id.

  2. Use of User instead of get_user_model(): In services/order.py, it's best practice to use get_user_model() instead of directly referencing User. This ensures compatibility with custom user models.

  3. Transaction Decorator: Consider using the @transaction.atomic decorator for better readability and to ensure that the entire function executes within a single transaction context.

  4. Type Annotations: Improve code clarity by specifying the type of QuerySet returned in functions like get_orders.

  5. Typo: There's a typo in the get_taken_seats function (tiket should be ticket). Correcting this will prevent potential errors.

  6. Nullable user Field in Order Model: The change to allow null and blank values for the user field in the Order model is significant. Ensure this aligns with your application's logic and requirements.

Please address these issues to ensure the code fully meets the task requirements and constraints. Once these are resolved, your code will be in great shape! Keep up the great work! 🚀

✨ Please rate this review in the Platform's notification center. I will be grateful for your feedback! ✨

🔄 Fix the issues, commit the changes, and then re-request my review using the Re-request review button in the Reviewers tab.

Comment on lines +19 to +44
migrations.CreateModel(
name='User',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
],
options={
'verbose_name': 'user',
'verbose_name_plural': 'users',
'abstract': False,
},
managers=[
('objects', django.contrib.auth.models.UserManager()),
],
),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The User model is being created here, but it seems to duplicate the default Django User model. If you intend to extend the default User model, consider using a custom user model by extending AbstractUser or AbstractBaseUser instead of creating a new model from scratch.

Comment on lines +49 to +50
('created_at', models.DateTimeField(auto_now_add=True)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='orders', to=settings.AUTH_USER_MODEL)),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Order model references settings.AUTH_USER_MODEL for the user field, which is correct. Ensure that AUTH_USER_MODEL is set to the correct user model in your settings if you are using a custom user model.

Comment on lines 87 to 88
('movie_session', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='db.moviesession')),
('order', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='db.order')),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Ticket model has a foreign key to Order. Ensure that the Order model is correctly defined and migrated before this migration is applied to avoid any dependency issues.

Comment on lines +91 to +93
migrations.AddConstraint(
model_name='ticket',
constraint=models.UniqueConstraint(fields=('row', 'seat', 'movie_session'), name='unique_ticket'),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The unique constraint on the Ticket model ensures that each combination of row, seat, and movie_session is unique. This is a good practice to prevent duplicate tickets for the same seat in a session.

Comment on lines +17 to +18
name='user',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='orders', to=settings.AUTH_USER_MODEL),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The user field in the Order model is now nullable and can be left blank. This means an Order can exist without being associated with a User. Ensure this change is intentional and that your application logic can handle orders without users.

raise Exception("No tickets to create")

with transaction.atomic():
user = User.objects.get(username=username)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The User.objects.get(username=username) call can raise a DoesNotExist exception if the user is not found. Consider handling this exception to provide a more user-friendly error message.

Comment on lines 32 to 33
except ValidationError as e:
raise ValueError(f"Invalid ticket data: {e}")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Raising a ValueError with a custom message is a good practice here, as it provides clear feedback about the validation error. Ensure that this exception is handled appropriately where the create_order function is called.


def get_orders(username: str = None) -> list:
if username:
user = User.objects.get(username=username)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the create_order function, User.objects.get(username=username) can raise a DoesNotExist exception. Consider handling this exception to ensure smooth operation when the user is not found.

services/user.py Outdated


def get_user(user_id: int) -> User:
return User.objects.get(pk=user_id)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The get_user function uses User.objects.get(), which will raise a DoesNotExist exception if no user is found with the given ID. Consider handling this exception or documenting that this function may raise an exception if the user is not found.

services/user.py Outdated
Comment on lines 49 to 50
except ObjectDoesNotExist:
raise ObjectDoesNotExist(f"User with id {user_id} does not exist.")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Raising ObjectDoesNotExist in the update_user function is redundant since this exception is already raised by User.objects.get(). Consider raising a more specific exception or handling it differently to provide clearer feedback.

Copy link

@mateacademy-ai-mentor mateacademy-ai-mentor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your hard work on this Pull Request! 🎉 While the decision is to APPROVE to help you move forward with your learning journey, there are several critical issues that need to be addressed to ensure your code aligns with best practices and application requirements:

  1. User Model Creation: Avoid creating a custom User model directly in the migration file. Instead, define it in models.py and create migrations to ensure better maintainability and integration with Django's authentication system.

  2. Order Model's User Field: The user field in the Order model allows null and blank values and uses on_delete=CASCADE. Ensure these behaviors align with your application's logic, as they allow orders to exist without an associated user and delete all related orders if a user is deleted.

  3. Exception Handling: Use User.DoesNotExist instead of ObjectDoesNotExist for clarity and specificity in exception handling. Also, ensure that exceptions are handled in a way that aligns with your application's error handling strategy.

  4. Type Annotations: Update the type annotations for genres_ids and actors_ids to list[int] for consistency and clarity. Also, ensure the return type of get_orders is annotated as QuerySet instead of list.

  5. Use of get_user_model(): It's best practice to use get_user_model() instead of directly referencing User to ensure compatibility with custom user models.

  6. Import Statement: Ensure the import statement for AUTH_USER_MODEL is from django.conf import settings for compatibility with Django's settings.

Please review these comments and make the necessary improvements to enhance your code. Keep up the great work, and continue learning from these experiences! 🚀

✨ Please rate this review in the Platform's notification center. I will be grateful for your feedback! ✨

Comment on lines +19 to +44
migrations.CreateModel(
name='User',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
],
options={
'verbose_name': 'user',
'verbose_name_plural': 'users',
'abstract': False,
},
managers=[
('objects', django.contrib.auth.models.UserManager()),
],
),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating a custom User model directly in the migration file is not recommended. Define the model in models.py and then create migrations. This ensures better maintainability and integration with Django's authentication system.

Comment on lines +49 to +50
('created_at', models.DateTimeField(auto_now_add=True)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='orders', to=settings.AUTH_USER_MODEL)),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The user field in the Order model uses on_delete=CASCADE. Ensure this behavior aligns with your application's logic, as deleting a user will also delete all related orders.

Comment on lines +17 to +18
name='user',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='orders', to=settings.AUTH_USER_MODEL),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The user field in the Order model is now set to allow null and blank values. Ensure this change aligns with your application's logic, as it allows orders to exist without an associated user.

db/models.py Outdated
from django.core.exceptions import ValidationError
from django.db.models import UniqueConstraint

from settings import AUTH_USER_MODEL

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The import statement for AUTH_USER_MODEL should be from django.conf import settings instead of from settings import AUTH_USER_MODEL. This ensures compatibility with Django's settings.

db/models.py Outdated
Comment on lines 62 to 66
user = models.ForeignKey(AUTH_USER_MODEL,
on_delete=models.CASCADE,
null=True,
blank=True,
related_name="orders")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The user field in the Order model allows null and blank values. Ensure this behavior is intentional and aligns with your application's logic, as it allows orders to exist without an associated user.

with transaction.atomic():
try:
user = User.objects.get(username=username)
except ObjectDoesNotExist:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using User.DoesNotExist instead of ObjectDoesNotExist for clarity and specificity in exception handling.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree

if username:
try:
user = User.objects.get(username=username)
except ObjectDoesNotExist:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using User.DoesNotExist instead of ObjectDoesNotExist for clarity and specificity in exception handling.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree

return order


def get_orders(username: str = None) -> list:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return type of get_orders should be annotated as QuerySet instead of list for accuracy.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree

def get_user(user_id: int) -> User:
try:
return User.objects.get(pk=user_id)
except ObjectDoesNotExist:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using User.DoesNotExist instead of ObjectDoesNotExist for clarity and specificity in exception handling.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree


user.save()
return user
except ObjectDoesNotExist:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using User.DoesNotExist instead of ObjectDoesNotExist for clarity and specificity in exception handling.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree

db/models.py Outdated
from django.core.exceptions import ValidationError
from django.db.models import UniqueConstraint

from settings import AUTH_USER_MODEL

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import settings from django.conf


with transaction.atomic():
try:
user = User.objects.get(username=username)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use get_user_model(), not User

Link

Comment on lines 35 to 39
for ticket in create_tickets:
try:
ticket.full_clean()
except ValidationError as e:
raise ValueError(f"Invalid ticket data: {e}")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You already have validation on model level for this. Read how save method works in models

Comment on lines +38 to +39
user = User.objects.get(pk=user_id)
if username:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use get_user method here

Copy link

@Arsen-hrynevych Arsen-hrynevych left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly correct

with transaction.atomic():
try:
user = User.objects.get(username=username)
except ObjectDoesNotExist:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree

print(f"Movie session with id {session_id} does not exist.")


def get_taken_seats(movie_session_id: int) -> list:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree

if username:
try:
user = User.objects.get(username=username)
except ObjectDoesNotExist:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree

return order


def get_orders(username: str = None) -> list:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree

def get_user(user_id: int) -> User:
try:
return User.objects.get(pk=user_id)
except ObjectDoesNotExist:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree


user.save()
return user
except ObjectDoesNotExist:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree

Comment on lines 27 to +29
"db",
"django.contrib.auth",
"django.contrib.contenttypes",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

db should be the last one in the list

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants