I need your help in such question:
This is my models.py:
class Location(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1)
name = models.CharField(max_length=100, verbose_name="Локация", default=u'')
photos = models.ImageField(upload_to='photos', null=True)
This is my forms.py:
class LocationForm(forms.ModelForm):
class Meta:
model = Location
fields = ['name', 'photos']
This is my views.py:
class AddLocationPageView(FormView):
template_name = 'add_location.html'
form_class = LocationForm
def form_valid(self, form):
form.save()
return super(AddLocationPageView, self).form_valid(form)
I need to have possibility of uploading several photos at the time.
How can I do that?
Thanks!
Since I'm assuming you're using a relational database and your model field name is 'photos' you'll want more than one photo per location.
You can do something like:
class Image(models.Model):
full_size = models.ImageField()
thumbnail = models.ImageField()
location = models.ForeignKey('app_label.Location', related_name='photos')
and remove the image field from the Location model.
To upload multiple photos, you'll want to use a formset. Depending on the interface you want, you'll probably want to use a model formset so the photos get their location_id set properly.
With your form, all you need to do is use the formset_factory function that you can call in your view (probably in get_context_data).
Handling the formset in your view involves some logic wrangling but there is a project called django-extra-views that implements the form with a formset logic, again, depending on the interface you're going for here.
If you want to just add photos to a pre-existing location, that is much simpler: just include the model_formset with a location object.
Related
I have the model created for complaints. I tried a few methods to help a user create the complaint, but nothing works so I have given up and I just want to understand what to add in the views.py so that I can do that. The system basically has multiple users and I want the users to send in their complaints to the admin panel, so that they can be viewed, edited or deleted as per use on the dashboard. Right now my form does get created but it does not save the complaints in the admin panel.
models.py:
class Complaints(models.Model):
user = models.ForeignKey(User, on_delete= CASCADE, null = True, blank=True)
title = models.CharField(max_length=300)
description = models.TextField(null=True, blank= True)
highpriority = models.BooleanField(default=False)
document = models.FileField(upload_to='static/documents')
def __str__(self):
return self.title
what to add in the views.py? I've tried various things but I don't know what to do to make it work.
this if my views.py but I feel like the entire thing is wrong so I want an entirely new views:
class ComplaintCreate(CreateView):
model = Complaints
form = ComplaintForm
fields = '__all__'
success_url = reverse_lazy('New')
template_name = 'new.html'
I want the final page to look like this:
there is not form attribute in CreateView change form to form_class
class ComplaintCreate(CreateView):
model = Complaints
form_class = ComplaintForm
fields = '__all__'
success_url = reverse_lazy('New')
template_name = 'new.html'
From my little knowledge on how serializers work, I know we mostly use modelserializers, and for that, we would have a model for all we want to serialize but how can I join all the images in the different models and then serialize them.
These are my models
class Vendors(models.Model):
title = models.CharField(max_length=50, blank=False)
image = models.ImageField(upload_to='static/vendors', blank=True, null=True)
class Riders(models.Model):
title = models.CharField(max_length=50, blank=False)
image = models.ImageField(upload_to='static/riders', blank=True, null=True)
class VendorsRiders(models.Model):
VendorImg = models.ForeignKey(Vendors, on_delete=models.CASCADE)
RiderImg = models.ForeignKey(Riders, on_delete=models.CASCADE)
This is my serializer
Class VendorsRidersSerializers(models.Model):
Class Meta:
model = VendorsRiders
fields = '__all__'
So, how to get all the images to the endpoint i would specify ? since, I'm a beginner in DRF I also need a suggestion and advice on the best practice to do this. Thank you
With defining fields = '__all__' in a serializer you just have access to properties of your model. One way to serialize your image fields of related models is to define SerializerMethodField Like:
Class VendorsRidersSerializers(models.Model):
rider_image = serializers.SerializerMethodField()
Class Meta:
model = VendorsRiders
fields = '__all__'
def get_rider_image(self, obj):
req = self.context['request']
# build_absolute_uri will convert your related url to absolute url
return req.build_absolute_uri(obj.VendorImg.image.url)
Also note that you should pass the request from your view to context of your serializer to build an absolute url (Example: VendorsRidersSerializers(queryset, many=True, context={'request': self.request}) or override the get_serializer_class method and pass the request to it's context) and then use the data of this serializer.
I'm on my second Django project. On my first project I used all generic views, with only the most basic forms tied directly to a custom user model using UpdateView.
In this project I'm trying to implement user profile functionality. My custom user model has some extra dummy fields just so I can manipulate the data. This I refer so as the CustomUser model. I also have a UserAddress model containing addresses since a user can have more than one address. I have tried looking for other questions, and I get similar questions, but there is always something missing:
Django class based views - UpdateView with two model forms - one submit
Using Multiple ModelForms with Class-Based Views
Multiple Models in a single django ModelForm?
Django: multiple models in one template using forms
I've spent the last day or two looking for the "Django way" of doing what I want to do and have had no luck. My initial thought was that I could use a single template, fed with two ModelForms wrapped in a single <form> tag. The view would then process each form and update the CustomUser model and create or update the UserAddress models. I have figured out how to mash together the functionality using the base View CBV, but I suspect I'm duplicating a lot of functionality that I could probably find already done in Django. This is my view, where I handle the form instantiating manually, and feed the context.
class UserDetailsView(View):
def get(self, request):
user = request.user
user_basic = CustomUser.objects.get(pk=user.pk)
basic_form = UserBasicForm(instance=user_basic)
user_address = UserAddress.objects.get(user=user.pk)
billing_address_form = UserAddressForm(instance = user_address)
context = {'basic_form':basic_form,'billing_address_form':billing_address_form}
return render(request, 'mainapp/profile.html', context)
My post is the same at this point, as I haven't done the actual validation and saving yet.
class UserBasicForm(forms.ModelForm):
class Meta(forms.ModelForm):
model = CustomUser
fields = (
'username',
'first_name',
'last_name',
)
labels = {
'username':'Username',
'first_name':'First Name',
'last_name':'Last Name',
}
class UserAddressForm(forms.ModelForm):
class Meta(forms.ModelForm):
model = UserAddress
fields = (
'description',
'addressee',
'company',
'address_1',
'address_2',
'city',
'prov_state',
'post_zip',
'country',
)
labels = {
'description':'Address Description',
'addressee':'Addressee',
'company':'Company Name',
'address_1':'Address',
'address_2':'Address 2',
'city':'City',
'prov_state':'Province or State',
'post_zip':'Postal or Zip Code',
'country':'Country',
}
class CustomUser(AbstractUser):
objects = CustomUserManager()
def __str__(self):
return self.email
class UserAddress(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE,)
description = models.CharField(max_length = 256, default='Description')
addressee = models.CharField(max_length = 256,)
company = models.CharField(max_length = 256, default='Self')
address_1 = models.CharField(max_length = 256,)
address_2 = models.CharField(max_length = 256,)
city = models.CharField(max_length = 256,)
prov_state = models.CharField(max_length = 256,)
post_zip = models.CharField(max_length = 256,)
country = models.CharField(max_length = 256,)
def __str__(self):
return self.description
Please go easy on me, I'll take most advice offered.
Edit
After reviewing some other SO questions and Django form examples, it appears that the final answer probably isn't SO material. That said, my observation is that for the Django built-in CBVs, the "best" base view is that which you can minimize or simplify the code you add. Using a TemplateView or FormView for my project in this case just depends on which methods I choose to re-write or override and for that, I'm still open to suggestions.
I'd do something like this (with betterforms):
class UserCreationMultiForm(MultiModelForm):
form_classes = {
'basic': UserBasicForm,
'address': UserAddressForm,
}
class UserDetailsView(View):
template = "mainapp/profile.html"
form_class = UserCreationMultiForm
success_url = reverse_lazy('home')
def form_valid(self, form):
# Save the user first, because the profile needs a user before it
# can be saved.
user = form['basic'].save()
address = form['address'].save(commit=False)
address.user = user
address.save()
return redirect(self.get_success_url())
Then rename your forms in your template to form.basic and form.address
I am new to django and I'm making food recipe app. I want the users to be able to add their own recipe.
models.py
from django.db import models
from django.core.urlresolvers import reverse
class Recipe(models.Model):
def __unicode__(self):
return self.recipe_name
recipe_name = models.CharField(max_length=250)
category = models.CharField(max_length=50)
description = models.CharField(max_length=1000)
image = models.CharField(max_length=1000)
prep_time = models.CharField(max_length=250)
difficulty = models.CharField(max_length=50)
instructions_url = models.CharField(max_length=1000)
def get_absolute_url(self):
return reverse('detail', kwargs={'pk': self.pk})
class Ingredients(models.Model):
def __unicode__(self):
return self.ingredients
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)
ingredients = models.CharField(max_length=1000)
views.py
class RecipeCreate(CreateView):
model = Recipe
fields = ['recipe_name', 'category', 'image', 'prep_time', 'difficulty', 'instructions_url']
At the moment my form display the fields only from my "class Recipe", but what i want is to have Ingredient field with option to add additional fields. Do you have any suggestions how to do this? Thanks!
It's going to be difficult to do that with the generic CreateView which is meant to create just one instance of a model.
What you want is a view (you could use the generic Django View) with a form (ModelForm) for your Recipe and a formset (see Django formsets) for multiple Ingredients forms. In your View's post method you then validate all the forms and save the data.
In your HTML, you'll need to create additional fields dynamically using javascript and update the number of formsets accordingly (in the formset's management form)
I'm not sure to save my ManyToMany relationship. I found my exact problem in this thread: Django embedded ManyToMany form, except instead of Sales and Products models, I have models that make up a movie.
I tried the solution, but I receive a syntax error. I don't understand how Django should link the EquipmentModel, LightModel, and ActorModel to the ManyToMany relationship in MovieModel. So far (before trying the other thread's solution), the CharFields that are displayed on the form for LightModel, EquipmentModel, and ActorModel are not linked to the ManyToManyField in MovieModel. So when I save the forms and try to access a particular Movie's actors, all I see is a blank list. The solution from the other thread seems to make sense since it tries to link the models to the ManyToMany relationship in MovieModel, but I don't understand how Django knows which MovieModel to add to (how does it get the correct movieID?).
On a side note, is there a way to check for duplicate movies when the user presses the 'Submit' button on the form? I want to avoid creating duplicates.
views.py:
def add_movie(request, movieID=""):
if request.method == "POST":
form = MovieModelForm(request.POST)
eform = EquipmentModelForm(request.POST)
lform = LightModelForm(request.POST)
aform = ActorModelForm(request.POST)
print 'checking form'
print request.POST.items()
if form.is_valid() and eform.is_valid() and lform.is_valid() and aform.is_valid():
print 'form is valid'
movie_to_add = form.save()
e = eform.save()
l = lform.save()
a = aform.save()
movie_to_add.actors.add(a)
movie_to_add.lights.add(l)
movie_to_add.equipments.add(e)
# return HttpResponseRedirect('/data')
else:
# code for create forms ....
return render_to_response('add_movie.html', {'form':form, 'eform':eform,'lform':lform, 'aform':aform,}, context_instance=RequestContext(request))
Other code that may help:
forms.py
class LightModelForm(forms.ModelForm):
class Meta:
model = LightModel
class ActorModelForm(forms.ModelForm):
class Meta:
model = ActorModel
class EquipmentModelForm(forms.ModelForm):
class Meta:
model = EquipmentModel
class MovieModelForm(forms.ModelForm):
class Meta:
model = MovieModel
fields = ("title", "rank")
models.py
class EquipmentModel(models.Model):
equip = models.CharField(max_length=20)
class ActorModel(models.Model):
actor = models.CharField(max_length=20)
class LightModel(models.Model):
light = models.CharField(max_length=20)
class MovieModel(models.Model):
rank = models.DecimalField(max_digits=5000, decimal_places=3)
title = models.CharField(max_length=20)
equipments = models.ManyToManyField(EquipmentModel, blank=True, null=True)
actors = models.ManyToManyField(ActorModel, blank=True, null=True)
lights = models.ManyToManyField(LightModel, blank=True, null=True)
def __str__(self):
return self.title
Edit: removed unnecessary init and fields thanks to DTing
Edit2: Fixed!
There is a whole lot of stuff going wrong here in addition to what spulec said.
Your models.py look okay.
class EquipmentModel(models.Model):
equip = models.CharField(max_length=20)
class ActorModel(models.Model):
actor = models.CharField(max_length=20)
class LightModel(models.Model):
light = models.CharField(max_length=20)
class MovieModel(models.Model):
rank = models.DecimalField(max_digits=5000, decimal_places=3)
title = models.CharField(max_length=20)
equipments = models.ManyToManyField(EquipmentModel, blank=True, null=True)
actors = models.ManyToManyField(ActorModel, blank=True, null=True)
lights = models.ManyToManyField(LightModel, blank=True, null=True)
def __str__(self):
return self.title
You don't need to override the __init__ method on forms if you are not changing anything on init. You also don't need to be explicit about the fields if you want to include them all.
class LightModelForm(forms.ModelForm):
class Meta:
model = LightModel
class ActorModelForm(forms.ModelForm):
class Meta:
model = ActorModel
class EquipmentModelForm(forms.ModelForm):
class Meta:
model = EquipmentModel
class MovieModelForm(forms.ModelForm):
class Meta:
model = MovieModel
fields = ("title", "rank")
your view doesn't really make sense unless for every movie you are trying to add you also want to:
add a new movie to the db using the submitted post data
create one actor object and add to db
create one light object and add to db
create one equipment object and add to db
take those three objects and add them to another movie's m2m relationships.
This other movie is some movie that you pulled from the urlconf and passed to your view, not the one you just created.
This all seems a little strange.
what i think you want to do is create all the equipment, actors and lights objects so they are in your db already, and use the default m2m formfield widget to select them when adding a movie.
so:
forms.py
class MovieModelForm(forms.ModelForm):
class Meta:
model = MovieModel
urls.py:
url(r'^add_movie/$', add_movie)
views.py:
def add_movie(request):
if request.method=='POST':
form = MovieModelForm(request.POST)
if form.is_valid():
form.save()
return HttpResponse('success')
else:
form = MovieModelForm()
context = {'form':form }
return render_to_response('some_template.html', context,context_instance=RequestContext(request))
you could combine adding actors, lights, and equipment into the same form but that's a bit much for me to write out right now.
As far as modifying your original code to add those lights, actors, and equipment to the movie you just created, you could do this:
if form.is_valid() and eform.is_valid() and lform.is_valid() and aform.is_valid():
new_movie = form.save()
e = eform.save()
l = lform.save()
a = aform.save()
new_movie.actors.add(a)
new_movie.lights.add(l)
new_movie.equipments.add(e)
Change it to:
movie_to_add = get_object_or_404(MovieModel, id=movieID)