Either provide a url or define a get_absolute_url method on the Model - django-forms

Trying to have the user who wants to update a product that they already created, to be able to update and be redirected to a page.
HERE IS THE ERROR I'M RUNNING INTO:
Exception Type: NoReverseMatch
Exception Value:
Reverse for 'updatelisting' not found. 'updatelisting' is not a valid view function or pattern name.
HERE IS MY FORMS.PY FILE:
class ProductForm(ModelForm):
class Meta:
model = listing
fields = '__all__'
HERE IS MY VIEWS.PY FILE WITH THE RELATED VIEW:
from django.views.generic import UpdateView
class UpdateListing(UpdateView):
model = listing
template_name = 'update_listing.html'
fields = '__all__'
HERE IS MY URLS.PY FILE WITH THE RELATED URLS TO THE RELATED VIEWS:
I have set the urls main name to vendor.
app_name = 'vendor'
path('createlisting/', views.index, name='index'),
path('renderindex/', views.renderindex, name='renderindex'),
path('listing/edit/<int:pk>', views.UpdateListing.as_view(), name='updatelisting'),
HERE IS MY MODELS.PY FILE WITH THE RELATED MODEL TO THIS PROBLEM:
class listing(models.Model):
image = models.ImageField(blank=True, null=True)
name = models.CharField(max_length=255)
description = models.TextField()
unit_price = models.DecimalField(max_digits=6, decimal_places=2, validators=[MinValueValidator(1)])
inventory = models.IntegerField()
last_update = models.DateTimeField(auto_now=True)
collection = models.ForeignKey(Collection, on_delete=models.PROTECT, blank=True, null=True)
vendors = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=False)
def get_absolute_url(self):
return reverse('updatelisting', args=(str(self.id)))
It's funny because when I refresh the page it then says that the 'updatelisting' is not a pattern name or view name but it is a pattern name, I'm not sure why it is not identifying the pattern name which is ( updatelisting ). If you need anymore info let me know please. I thankyou for the help!

Related

DRF - Add User to a model with ManyToManyField

I am trying to implement a feature to my backend and allow the owner of private "Group" to add other users by their usernames instead of ID's and allow them to add their images to FileField only once after they were added to the model. The code I have so far:
models.py
class Group(models.Model):
group_name = models.CharField(max_length=255)
group_text = models.TextField(max_length=360, blank=True)
owner = models.ForeignKey(
settings.AUTH_USER_MODEL, related_name='owner_user', on_delete=models.SET(get_deleted_user), default=1)
created_on = models.DateTimeField(auto_now_add=True, null=True)
shared_to = models.ManyToManyField(UserProfile, blank=True, related_name='shared_to_user', null=True)
def __str__(self):
return self.group_name
def save(self, *args, **kwargs):
super(Group, self).save(*args, **kwargs)
class GroupImage(models.Model):
group_file = models.FileField(blank=True, null=True,
upload_to='media/covers/%Y/%m/%D/')
gallery_group = models.ForeignKey(Group, related_name='images', on_delete=models.CASCADE)
serializers.py
class GroupImageSerializer(serializers.ModelSerializer):
class Meta:
model = models.GroupImage
fields = ('group_file', )
class SharedToSerializer(serializers.ModelSerializer):
class Meta:
model = models.Group
fields = ('shared_to', )
class GroupSerializer(serializers.ModelSerializer):
images = GroupImageSerializer(many=True, read_only=True)
person = SharedToSerializer(many=True, read_only=True)
class Meta:
model = models.Group
fields = ('id', 'group_name', 'group_text', 'person', 'images')
def create(self, validated_data):
images_data = self.context.get('view').request.FILES
owner_id = self.context['request'].user.id
gallery_group = models.Group.objects.create(group_name=validated_data.get('group_name', 'no-
group_name'), group_text=validated_data.get('group_text'), owner_id=1)
for image_data in images_data.values():
models.GroupImage.objects.create(gallery_group=gallery_group,
group_file=image_data)
return gallery_group
views.py
class GroupCreateAPIView(generics.CreateAPIView):
queryset = models.Group.objects.all()
serializer_class = serializers.GroupSerializer
permission_classes = [AllowAny]
So if your only requirement is how to add users by their username and not their id. You should use SlugRelatedField. I also feel your serializer naming convention is quite confusing. Below is the serializer for Group model that can add users to a group.
class GroupSerializer(Serializer):
... other fields here
shared_to = models.SlugRelatedField(queryset = UserProfile.objects.all(), many=True, slug_field="username", allow_empty=True)
So first checkout SlugRelatedField. This basically is used to map to objects using a specific field of that object(username in this case). You will then get all the UserProfile instances in the shared_to field of the validated_data
property of the serializer which you can fetch in create method and add to you group. And then in the file upload api for your group you can check whether this user belongs to the group or not for permission checking.

Saving(create,update) along with foreignkey value from another model which is related user model

It may be a challenging question if you didn't get rightly. Here I have three models in which department model should be created by taking its place name from Place model which is related to the staff model. The Staff Model is in a OneToOneField relationship with User, so when a user creates a department the place name should be passed like HiddenField in HTML . This place name is related to place model with the user with GenericForeignKey. i have created a serializer which is not working as expected, it is returning the place name ,
.
In shortly I want to create a department while place should be selected from current user ID
class Staff(BaseModel):
ROLES = [
('ADMIN', 'Admin'),
('TEACHER', 'Teacher')
]
auth_user = models.OneToOneField(User, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
school_content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
school_id = models.PositiveIntegerField()
school = GenericForeignKey('school_content_type', 'school_id')
role = models.CharField(null=True, blank=True, choices=ROLES, max_length=20)
class Places(BaseModel):
name = models.CharField(max_length=50)
code = models.CharField(max_length=12, unique=True)
class Department(BaseModel):
TYPES = [
('ONLINE', 'Online'),
('OFFLINE', 'OfFline')
]
department_type = models.CharField(max_length=15, choices=TYPES)
service_no = models.CharField(max_length=50)
instructions = models.TextField(null=True, blank=True)
place = models.ForeignKey(Places, to_field='code', db_column='place_code', on_delete=models.PROTECT)
SERIALIZERS
class DepartmentCreateSerializer(serializers.ModelSerializer):
place_code=serializers.CharField(read_only=True)
class Meta:
model=Department
fields = ('department_type','service_no','instructions')
def get_place(self, request):
user_id=self.context['request'].user.id
school_id=Staff.objects.get(auth_user_id= user_id).school_id
places_code_name=Places.objects.get(id= school_id).name
class PlacesSerializer(serializers.ModelSerializer):
class Meta:
model = Places
fields = ('id', 'code', 'name')
from places.serializers import PlacesSerializer
class DepartmentCreateSerializer(serializers.ModelSerializer):
place= PlacesSerializer(read_only=True)
class Meta:
model=Department
fields = ('place','service_no','instructions')
def validate(self, attrs):
palce_obj = self.context['request'].user.staff.place()
attrs.update({'place': place_obj})
attrs = super().validate(attrs)
if not attrs.get('place', None):
raise serializers.ValidationError({'place': ["Place required"]})
return attrs

How to restrict fields when creating post request in DRF?

I am making a POST api using DRF. In that api, I need only few fields(name, size, customer_name, customer_address), but don't require this fields(status, ordered_time) because these fields I want to save these fields in run time as status='open' and ordered_time=DateTimeField.now()
views.py
class PizzaOrderCustomerView(APIView):
def post(self, request):
orders = request.data.get('orders')
# Create an article from the above data
serializer = ArticleSerializer(data=orders)
if serializer.is_valid(raise_exception=True):
article_saved = serializer.save()
return Response({"success": "Article '{}' created successfully".format(article_saved.name)})
models.py
class PizzaOrder(models.Model):
name = models.CharField(max_length=120)
size = models.CharField(max_length=10, choices=SIZE_CHOICE, default='MEDIUM')
customer_name = models.CharField(max_length=120)
customer_address = models.TextField()
ordered_time = models.DateTimeField(default=timezone.now, editable=False)
status = models.CharField(max_length=20, default='open', editable=False)
serializers.py
class OrderSerializer(serializers.ModelSerializer):
class Meta:
model = PizzaOrder
# fields = '__all__'
read_only_fields = ('status',)
But when I try to create an order, it needed status and ordered_time also. But it should save at the time of creating order automatically.
Suggest a good way to do it.
from rest_framework import viewsets, mixins
class PizzaViewsets(viewsets.ViewSet, mixins.CreateModelMixin):
model = PizzaOrder
serializer_class = OrderSerializer
queryset = model.objects.all(
serializer, it is always good practise to mention all fields instead of
all
class OrderSerializer(serializers.ModelSerializer):
class Meta:
model = PizzaOrder
fields = ('status','ordered_time','name', 'size', 'customer_name', 'customer_address',)
read_only_fields = ('status','ordered_time',)

Handling viewset that has a serializer with multiple foreignkeys

I have this serializer:
class ReviewSerializer(serializers.ModelSerializer):
user = UserSerializer(read_only=True)
class Meta:
model = Review
fields = ('pk', 'title', 'user', 'movie', 'timestamp', 'review_text',)
I want to mention that user and movie are both ForeignKeys defined in models.py for Review model. Here is the model:
class Review(models.Model):
title = models.CharField(max_length=255)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='reviews')
movie = models.ForeignKey(Movie, on_delete=models.CASCADE, related_name='reviews')
review_text = models.TextField()
timestamp = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '{movie} review by {user}'.format(user=self.user, movie=self.movie)
I want to create a viewset, but if I do something like this:
class ReviewsViewSet(viewsets.ModelViewSet):
queryset = Movie.objects.all()
serializer_class = ReviewSerializer
and register it like this:
router.register(r'reviews', views.ReviewsViewSet, 'reviews')
won't work, it requires me to provide a movie field as logged here:
AttributeError at /api/reviews/
Got AttributeError when attempting to get a value for field `movie` on serializer `ReviewSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `Movie` instance.
Original exception text was: 'Movie' object has no attribute 'movie'.
Thanks in advance.
Edited.

DRF - html post options only for user logged in

I have the following serializer:
class WidgetSerializer(serializers.ModelSerializer):
owner = serializers.HiddenField(default=serializers.CurrentUserDefault())
class Meta:
model=Widget
fields = ('id', 'title', 'description', 'username', 'code', 'owner', 'list')
The problem is that the 'list' field, which is a drop down, gives all lists whereas I only want it to display lists that are owned by the user currently logged in.
Here's the respective models:
class WidgetList(MPTTModel):
name = models.CharField(max_length=100)
description = models.CharField(max_length=1024)
owner = models.ForeignKey('MyUser')
parent = TreeForeignKey('self', null=True, blank=True, related_name='children', db_index=True)
def __str__(self):
return self.name
class MPTTMEta:
order_insertion_by = ['name']
class Widget(models.Model):
title = models.CharField(max_length=100)
description = models.CharField(max_length=1024)
username = models.CharField(max_length=50)
code = models.CharField(max_length=1024)
owner = models.ForeignKey('MyUser', related_name='MyUser_owner')
list = models.ForeignKey('WidgetList')
I am a beginner in django. I hope that I could help.
Just try this
WidgetList.objects.filter(owner=request.user)
I have to limit it through a SlugRelatedField as per the documentation here -
http://www.django-rest-framework.org/api-guide/relations/#slugrelatedfield
I then used it like so -
list = serializers.SlugRelatedField(
queryset=WidgetList.objects.filter(owner=3),
many=True,
slug_field='name'
)
All I need to figure out now is to pass the serializers.CurrentUserDefault() in the filter for the queryset, or pass request.user.

Resources