could someone tell me how to save multiple files in the post method of my form, I can only save 1 file, not the ones I have tried to upload.
Files = models.FileField(upload_to="alumno/archivos/%Y/%m/%d", null=True, blank=True, verbose_name='Archivos')
That's what the field is called in my model Student.
Then in my post method in the view I have the following code, but it doesn't save everything, as I said it only saves 1 file.
def post(self, request, *args, **kwargs):
data = {}
files = request.FILES.getlist('Files')
try:
action = request.POST['action']
if action == 'edit':
form = self.get_form()
for f in files:
Alumno.objects.update(Files=f)
data = form.save()
else:
data['error'] = 'No ha ingresado a ninguna opción'
except Exception as e:
data['error'] = str(e)
return JsonResponse(data)
In this case as it says update in Alumno.objects because I am doing the edit, I have the same problem as with the create. Please could someone help me? Regards
I want to be able to save or edit two or more files in the Pupil model.
I have managed to do it, but I have changed the way, previously the File field was one of the Alumno class
class Alumno (DatosBasicos):
cp = models.PositiveIntegerField(verbose_name='Código Postal', validators=[RegexValidator(r'^\d{1,5}$')])
monitores = models.ManyToManyField(Monitor, verbose_name='Monitor/es', max_length=250)
pagado = models.BooleanField(default=False)
foto = models.ImageField(upload_to='alumno/%Y/%m/%d', null=True, blank=True, verbose_name='Foto')
# files = models.FileField(upload_to='alumno/%Y/%m/%d', null=True, blank=True, verbose_name='Archivos')
# pagos_actividad_meses = models.ForeignKey(MesesPagados, on_delete=models.CASCADE)
class Meta:
verbose_name = 'Alumno'
verbose_name_plural = 'Alumnos'
ordering = ['id']
def __str__(self):
return self.get_full_name()
def get_full_name(self):
return '{} {}'.format(self.nombre, self.apellidos)
def get_image(self):
if self.foto:
return '{}{}'.format(MEDIA_URL, self.foto)
return '{}{}'.format(STATIC_URL, 'img/perfil_default.jpg')
def get_files_path(self):
# return '{}{}'.format(MEDIA_URL, self.Files)
return '{}alumno/%Y/%m/%d/{}'.format(MEDIA_ROOT, self.id)
def toJSON(self):
item = model_to_dict(self)
telf_convert = self.telf.as_national
item['telf'] = telf_convert
item['actividades'] = [{'id': g.id, 'nombre': g.nombre} for g in self.actividades.all()]
item['monitores'] = [{'id': g.id, 'nombre': g.nombre} for g in self.monitores.all()]
item['full_name'] = self.get_full_name()
item['foto'] = self.get_image()
item['Files'] = self.get_files_path()
return item
and in the post method of the view I had put the above code to add the file, but of course it only saved 1 file, the last one of the for cycle.
I think I was doing it wrong, so I made a new table with a relationship between Alumno and FileField.
class FilesAlumnos(models.Model):
alumno_files = models.ForeignKey(Alumno, on_delete=models.CASCADE, null=True, blank=True)
files = models.FileField(upload_to='alumno/%Y/%m/%d', null=True, blank=True, verbose_name='Archivos')
class Meta:
verbose_name = 'Archivo'
verbose_name_plural = 'Archivos'
ordering = ['id']
def get_files_path(self):
# return '{}{}'.format(MEDIA_URL, self.Files)
return '{}alumno/%Y/%m/%d/{}'.format(MEDIA_ROOT, self.id)
def toJSON(self):
item = model_to_dict(self)
item['Files'] = self.get_files_path()
return item
Now in the post method I do the following
class AlumnoUpdateView(LoginRequiredMixin, ValidatePermissionRequiredMixin, UpdateView):
model = Alumno
form_class = AlumnoForm
template_name = 'alumno/create.html'
success_url = reverse_lazy('general:alumno_list')
permission_required = 'general.change_alumno'
url_redirect = success_url
def dispatch(self, request, *args, **kwargs):
self.object = self.get_object()
return super().dispatch(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
data = {}
files = request.FILES.getlist('files')
try:
action = request.POST['action']
if action == 'edit':
form = self.get_form()
data = form.save()
for f in files:
new_file = FilesAlumnos.objects.create(alumno_files_id=data.get('id'), files=f)
new_file.save()
else:
data['error'] = 'No ha ingresado a ninguna opción'
except Exception as e:
data['error'] = str(e)
return JsonResponse(data)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['title'] = 'Edición de los datos del Alumno'
context['entity'] = 'Alumnos'
context['list_url'] = self.success_url
context['action'] = 'edit'
return context
The only problem I have now is in physically deleting the files, when I click on edit and change the files or delete an item.
Related
I am getting error AttributeError: 'Response' object has no attribute 'user' for the below code I have written
I am trying to get the user info from the context and create a notification model. I am getting the above error while returning the statement. I don't understand why I am getting this error
Model
class CourseNotification(models.Model):
uid = models.UUIDField(
primary_key=True,
default=uuid.uuid4,
editable=False,
unique=True)
course = models.ForeignKey('Course.Course', on_delete=models.SET_NULL, null=True)
user = models.ManyToManyField('Profile.myUser',null=True)
def get_user(self):
return [i for i in self.user.all()]
def __str__(self):
return self.course.course_title
View
class CourseNotificationView(ModelViewSet):
queryset = CourseNotification.objects.all()
serializer_class = CourseNotificationSerializer
authentication_classes = [JWTAuthentication]
permission_classes = [IsAuthenticated]
def get_queryset(self):
if self.request.user.email is not None:
profile = myUser.objects.get(email=self.request.user.email)
if profile is not None:
notification = CourseNotification.objects.filter(user=profile)
return notification
else:
return Response(data={"User": "Unauthorized User"}, status=HTTP_401_UNAUTHORIZED)
def retrieve(self, request, *args, **kwargs):
serializer = self.get_serializer(self.get_queryset(), many=True)
return Response(data=serializer.data)
Serializer
class CourseNotificationSerializer(serializers.ModelSerializer):
class Meta:
model = CourseNotification
fields = '__all__'
def create(self, validated_data):
users = self.context['request'].user
subject = validated_data['course']
if users is None and subject is None or subject == "":
raise serializers.ValidationError({"Invalid": "Subject could not be Invalid"})
checkNotification = self.checkNotification(users, subject)
if checkNotification is not None and checkNotification.status_code == 200:
return checkNotification
validate_subject = self.validateSubject(users, subject)
if validate_subject.status_code == 200:
return validate_subject
get_data = CourseNotification.objects.create(course=subject)
get_data.user.add(users)
get_data.save()
return Response(data=get_data, status=HTTP_201_CREATED, content_type="application/json")
#staticmethod
def checkNotification(users, subject):
get_data = CourseNotification.objects.filter(user=users, course=subject)
if get_data:
for data in get_data:
data.user.remove(users)
data.save()
return Response(data=get_data, status=HTTP_200_OK, content_type="application/json")
#staticmethod
def validateSubject(users, subject):
get_data = CourseNotification.objects.filter(course=subject).exclude(user=users)
if get_data:
subject = CourseNotification.objects.get(course=subject)
subject.user.add(users)
subject.save()
return Response(data=get_data, status=HTTP_200_OK, content_type="application/json")
I am trying to add data to the model through API. I am facing the problem
I am trying to create an eCommerce application. And for useraddress (Billing and shipping ) want something like below. Here have a model called Order and UserAddress , which is
class Order(models.Model):
cart = models.ForeignKey(Cart,on_delete=models.CASCADE)
user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
start_date = models.DateTimeField(auto_now_add=True)
ordered_date = models.DateTimeField()
ordered_total = models.PositiveIntegerField()
shipping_price = models.PositiveIntegerField(default=0)
ordered = models.BooleanField(default=False)
billing_address = models.ForeignKey(UserAddress,related_name='billing_address',on_delete=models.CASCADE)
shipping_address = models.ForeignKey(UserAddress,related_name='shipping_address',on_delete=models.CASCADE,default=None)
and
class UserAddress(models.Model):
BILLING = 'billing'
SHIPPING = 'shipping'
ADDRESS_TYPE = (
(BILLING , 'Billing'),
(SHIPPING, 'Shipping')
)
user = models.ForeignKey(UserCheckout,
on_delete=models.CASCADE)
name = models.CharField(max_length=50)
phone = models.CharField(max_length=21,null=True)
street_address = models.CharField(max_length=50)
home_address = models.CharField(max_length=50)
type = models.CharField(max_length=100,choices=ADDRESS_TYPE)
def __str__(self):
return self.user
def get_full_address(self):
return '{0}, {1},{2}'.format(self.name ,self.user,self.phone )
And my View is
class AddressFormView(FormView):
form_class = AddressForm
template_name = 'orders/address_select.html'
def dispatch(self, request, *args, **kwargs):
b_address, s_address = self.get_address()
if not (b_address.exists() and s_address.exists()):
messages.success(self.request, 'Please add an address before continuing')
return redirect('add_address') # redirect before checkout
return super(AddressFormView, self).dispatch(request, *args, **kwargs)
def get_address(self, *args, **kwargs):
user_checkout = self.request.session['user_checkout_id']
b_address = UserAddress.objects.filter(
type=UserAddress.BILLING, user_id=user_checkout)
s_address = UserAddress.objects.filter(
type=UserAddress.SHIPPING, user_id=user_checkout)
return b_address, s_address
def get_form(self):
form = super(AddressFormView, self).get_form()
b_address, s_address = self.get_address()
form.fields['billing_address'].queryset = b_address
form.fields['shipping_address'].queryset = s_address
return form
def form_valid(self, form, *args, **kwargs):
billing_address = form.cleaned_data['billing_address']
shipping_address = form.cleaned_data['shipping_address']
self.request.session['billing_address_id'] = billing_address.id
self.request.session['shipping_address_id'] = shipping_address.id
return super(AddressFormView, self).form_valid(form, *args, **kwargs)
def get_success_url(self):
return reverse('checkout')
And the above view used a form , which is
class AddressForm(forms.Form):
billing_address = forms.ModelChoiceField(queryset=UserAddress.objects.filter(type=UserAddress.BILLING),empty_label=None,widget=forms.RadioSelect)
shipping_address = forms.ModelChoiceField(queryset=UserAddress.objects.filter(type=UserAddress.SHIPPING),empty_label=None,widget=forms.RadioSelect)
But Now when i fetching the url http://127.0.0.1:8000/cart/address/ i have the above error. The code is form a github repo which is working correctly. But in my project i am using django Allauth package and Custom User Model, which the github project that i am following didn't use. I assume , this could be an issue , because the github repo didn't use that. So is there any hints or idea or any new way to do it.
The table order_useraddress in your database does not have the type column.
Have you tried migrating/updating the database?
python manage.py makemigrations
python manage.py migrate
I need to update my table every time a new value of "sku" is entered (not to create a new entry), but it does have to happen only if the "client" selected is the same. If the "client" is different, then the model should add a new object with the same "sku", but with different "clients".
I have tried to do the following in my models.py:
class ProductList(models.Model):
id_new = models.IntegerField(primary_key=True)
sku = models.CharField(primary_key=False, max_length=200)
client = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
name = models.CharField(max_length=256)
description = models.CharField(max_length=1000)
storage = models.CharField(max_length=256)
cost_price = models.CharField(max_length=256)
sell_price = models.CharField(max_length=256)
ncm = models.CharField(max_length=256)
inventory = models.IntegerField(null=True)
class Meta:
unique_together = (('sku', 'client'),)
But it is not working. How can I make that work?
You can try like this:
# form
class MyForm(forms.ModelForm):
class Meta:
model = ProductList
def save(self, *args, **kwargs:
client = self.cleaned_data.get('client') # get client from form cleaned_data
if hasattr(self.instance, 'pk') and self.instance.client != client: # check if client match's already existing instance's client
self.instance.pk = None # make a duplicate instance
self.instance.client = client # change the client
return super(MyForm, self).save(*args, **kwargs)
# views.py
# ...
def my_view(request, id):
instance = get_object_or_404(ProductList, id=id)
form = MyForm(request.POST or None, instance=instance)
if form.is_valid():
form.save()
return redirect('next_view')
return render(request, 'my_template.html', {'form': form})
Update
Um you can override the model as well. you can try like this:
# Untested Code but should work
def save(self, *args, **kwargs):
if self.pk:
current_instance = self.__class__.objects.get(pk=self.pk)
if current_instance.client != self.client:
self.pk = None
return super(ProductList, self).save(*args, **kwargs)
I'm having trouble incrementing the vote_score attribute of my model every time it is voted on. This is my model:
# idea model
class Idea(models.Model):
User = ('accounts.User')
creator = models.ForeignKey(User, related_name='ideas', on_delete=models.PROTECT)
title = models.CharField(max_length=100, null=True, blank=True)
vote_score = models.BigIntegerField(default=0, null=True, blank=True)
votes = VotableManager()
#vote model
class Vote(models.Model):
user = models.ForeignKey(AUTH_USER_MODEL)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey()
create_at = models.DateTimeField(auto_now_add=True)
vote = models.NullBooleanField()
objects = VoteManager()
class Meta:
unique_together = ('user', 'content_type', 'object_id')
#classmethod
def votes_for(cls, model, instance=None):
ct = ContentType.objects.get_for_model(model)
kwargs = {
"content_type": ct
}
if instance is not None:
kwargs["object_id"] = instance.pk
return cls.objects.filter(**kwargs)
#manager
_VotableManager(models.Manager):
def __init__(self, through, model, instance, field_name='votes', extra_field='vote_score'):
self.through = through
self.model = model
self.instance = instance
self.field_name = field_name
self.extra_field = extra_field
self.name = model.title
#instance_required
def up(self, user, vote):
with transaction.atomic():
if self.through.objects.filter(user=user, content_object=self.instance).exists():
c_type = ContentType.objects.get_for_model(self.instance)
vote_obj = self.through.objects.get(user=user, object_id=self.instance.id, content_type=c_type)
vote_obj.vote = vote
vote_obj.save()
self.instance.save()
else:
self.through(user=user, content_object=self.instance, vote=vote).save()
if self.extra_field:
setattr(self.instance, self.extra_field, F(self.extra_field)+1)
self.instance.save()
My goal is to have it so when the idea is created the creator automatically counts as 1 vote toward it so that falls under this view:
# idea create view
class IdeaCreateView(LoginRequiredMixin, CreateView):
model = Idea
form_class = IdeaCreateForm
template_name = 'idea_create.html'
success_url = 'success'
def dispatch(self, *args, **kwargs):
self.user = get_object_or_404(User, pk=kwargs['pk'])
return super(IdeaCreateView, self).dispatch(*args, **kwargs)
def form_valid(self, form):
idea = form.save(commit=False)
idea.creator = self.request.user
idea.save()
idea.votes.up(user=idea.creator, vote=True)
idea.vote_score += 1
return HttpResponseRedirect('success')
And then to allow other users to vote on it as well, which falls under this view:
#vote view
class IdeaVoteView(LoginRequiredMixin, CreateView):
form_class = VoteForm
required_fields = ('action',)
template_name = 'vote_confirm.html'
success_url = 'success'
def form_valid(self, form):
obj = Idea.objects.get(pk=self.kwargs['pk'])
user = self.request.user
user_id = self.request.user.pk
object_id = obj.pk
content_type_id = 10
form_class = VoteForm
self.vote = form.save(commit=False)
self.vote.user_id = user_id
self.vote.object_id = object_id
self.vote.content_type_id = content_type_id
if obj.votes.exists(user_id):
return HttpResponseRedirect('failure')
else:
self.vote.save()
obj.votes.up(user_id)
return HttpResponseRedirect('success')
def get_object(self, queryset=None):
obj = Idea.objects.get(pk=self.kwargs['pk'])
voters = obj.get_voters()
return voters
Why doesn't setting the extra_field attribute on the manager take care of this and what's going wrong in the views?
Wow, great news... After talking to myself for hours I figured it out. I created this model function:
def vote_up(self):
self.vote_score += 1
self.save()
The problem was I wasn't calling the save() method on this function so the increment wasn't getting saved! Really simple, but I glossed right over it. Anyway, maybe answering the question will help someone.
I need to assign multiple CampaignTypes to a Campaign unsing Django FormsModels.
Selecting many CapaignTypes at once, adding the CapaignTypes to only one campaign. Thanks I will appreciate any help
class Campaign(models.Model):
client_id = models.ForeignKey(Company)
name = models.CharField(max_length=45, null=True)
campaign_status = models.ForeignKey(CampaignStatus)
def __str__(self):
return self.name
class Campaign_type(models.Model):
campaign_type = models.CharField(max_length=45)
client_id = models.ForeignKey(Company)
campaign_id = models.ManyToManyField(Campaign, verbose_name='Campaign(s)')
def __str__(self):
return self.campaign_type + ' ' + str(self.client_id)
My code in form.py
class CampaignCampaignTypeForm(forms.ModelForm):
class Meta:
model = CampaignType
exclude = ['campaign_id', 'client_id']
campaign_type = forms.ModelMultipleChoiceField(queryset=CampaignType.objects.all())
def __init__(self, *args, **kwargs):
company = kwargs.pop("company")
if kwargs.get('instance'):
initial = kwargs.setdefault('initial', {})
initial['campaign_type'] = [t.pk for t in kwargs['instance'].campaing_type_set.all()]
forms.ModelForm.__init__(self, *args, **kwargs)
My code in view.py
def add_campaign_type_to_campaign(request, campaign_id):
if not request.user.is_authenticated():
return render(request, 'campaign/login.html')
else:
client_user = ClientUser.objects.get(client=request.user.pk)
form = CampaignCampaignTypeForm(data=request.POST or None, company=client_user.company)
if form.is_valid():
campaigntype = form.save(commit=False).clean()
#client_user = ClientUser.objects.get(client=request.user.pk)
campaign = Campaign.objects.get(id=campaign_id)
campaigntype.campaign_id = campaign
campaigntype.save()
form.save_m2m()
# return render(request, 'campaign/detail_campaign.html', {'campaign_type': campaign_type})
context = {
"form": form,
}
Do you try forms.SelectMultiple widget? Or if you can using Bootstrap on frontend, Select2 is a good JS package to help you on multiple selection.