I am working on a Django project with crispy forms.
I want to use images instead of the the default Models title/label to select a instance in a Many to Many relation form.
Content models.py:
class Cloth(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL)
title = models.CharField(max_length=200)
picture = ImageCropField(upload_to='cloth_pics/%Y-%m-%d/',
blank=True)
def __str__(self):
return self.title
class Outfit(models.Model):
owner = models.ForeignKey('profiles.Profile')
title = models.CharField(max_length=200)
cloths=models.ManyToManyField(Cloth)
Content forms.py
class ClothForm(forms.ModelForm):
class Meta:
model = Cloth
fields = ('title','type','picture')
class OutfitForm(forms.ModelForm):
class Meta:
model = Outfit
exclude= ["owner"]
Content views.py
def outfits_new(request):
if request.method == "POST":
form = OutfitForm(request.POST)
if form.is_valid():
outfit = form.save(commit=False)
outfit.owner = get_user(request)
outfit.created_date = timezone.now()
outfit.save()
pk=outfit.id
return HttpResponseRedirect(reverse('outfit_edit_delete', args=[pk]))
else:
cloths = Cloth.objects.filter(owner=request.user.id)
form = OutfitForm()
return render(request, '../templates/outfits_new.html', {'form': form, "cloths":cloths})
Content outfits_new.html
<form enctype="multipart/form-data" method="post">
{% csrf_token %}
{{ form|crispy }}
<div class="btn-group" role="group" aria-label="Basic example">
<input type="submit" value="Submit" name="edit" class="btn btn-success">
</div>
This code produces a Outfit form where I can select different cloths( displaying the cloths title). I want to select different cloths using a image from the cloths.picture field.
Thank you very much,
Patrick
Have a look at select2 at https://select2.github.io/examples.html. It allows you to do images in comboboxes
There is a Django package at https://github.com/applegrew/django-select2
Related
I am making a django project and I have a form for the User to add a Vehicle Manually that will be assigned to him. I also would like to had an option for the user to choose a vehicle based on the entries already present in the database.
vehicles/models.py
class Vehicle(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
nickname = models.CharField(unique = True, max_length=150)
date_joined = models.DateTimeField(default=timezone.now)
brand = models.CharField(max_length=150)
battery = models.CharField(max_length=150)
model = models.CharField(max_length=150)
def __str__(self):
return self.nickname
def get_absolute_url(self):
return reverse('vehicle-list')
class Meta:
db_table = "vehicles"
I created a form so the user can add his Vehicles as such:
vehicles/forms.py
class VehicleAddFormManual(forms.ModelForm):
class Meta:
model = Vehicle
fields = ('brand','model', 'battery', 'nickname')
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
self.fields['brand']
self.fields['model']
self.fields['battery']
self.fields['nickname']
The corresponding view:
vehicles/views.py
class AddVehicleViewManual(LoginRequiredMixin, CreateView):
model = Vehicle
form_class = VehicleAddFormManual
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
def form_valid(self, form):
form.instance.user = self.request.user
return super().form_valid(form)
The html file:
vehicles/templates/vehicles/vehicle_form.html
{% extends "blog/base.html" %}
{% block content %}
{% load crispy_forms_tags %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">New Vehicle</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Submit</button>
</div>
</form>
</div>
{% endblock content %}
I would like to add another form in which the user has a dropdown with option with the brands, models and batteries that already exist in the database. If there's a car in the database with brand: Tesla, model: Model 3, battery: 50 kWh, then it would appear in the dropbox as a choice for each field.
I'm not sure how to do this and sorry for the newbie question... Thanks in advance!
I once had to do something similar, but I needed a form which had one checkbox for each item in a list of externally-supplied strings. I don't know if this is the cleanest way, but I used python metaclasses:
class SockSelectForm(forms.Form):
#staticmethod
def build(sock_names):
fields = {'sock_%s' % urllib.parse.quote(name):
forms.BooleanField(label=name, required=False)
for name in sock_names}
sub_class = type('DynamicSockSelectForm', (SockSelectForm,), fields)
return sub_class()
In my get() method, I instantiate it as:
form = SockSelectForm.build(names)
and the corresponding form handling in the post() method is:
form = SockSelectForm(request.POST)
I suspect if you look under the covers of Django's ModelForm, you'd see something similar, but I couldn't use ModelForm because it's too closely tied to the model system for what I needed to do.
model.py
class DropdownModel(models.Model):
brand = models.CharField(max_length=150)
battery = models.CharField(max_length=150)
model = models.CharField(max_length=150)
def __str__(self):
return self.brand.
form.py
from .models import DropdownModel
all_brand = DropdownModel.objects.values_list('brand','brand')
all_battery = DropdownModel.objects.values_list('battery','battery')
all_model= DropdownModel.objects.values_list('model','model')
class DropdownForm(forms.ModelForm):
class Meta:
model = DropdownModel
fields = "__all__"
widgets = {
'brand':forms.Select(choices=all_brand),
'battery':forms.Select(choices=all_battery),
'model':forms.Select(choices=all_model),
}
view.py
from django.shortcuts import render
from .form import DropdownForm
# Create your views here.
def HomeView(request):
form = DropdownForm()
context = {'form':form}
return render(request,'index.html',context)
index.html
{% extends "base.html" %}
{% load static %}
{% block title %}
Index | Page
{% endblock title %}
{% block body %}
{{form.as_p}}
{% endblock body %}
Output-
Note- if u can't see updated values in dropdown do server restart because localhost not suport auto update value fill in dropdown it's supoorted on live server
Thank you
I'm having a little problem with the .save() method in Django. For 1 form it works, for the other it doesn't. And I can't find the problem.
views.py
#login_required
def stock_add(request, portfolio_id):
if request.method == 'POST':
print('request.method is ok')
form = StockForm(request.POST)
print('form is ok')
if form.is_valid():
print('form is valid')
stock = form.save(commit=False)
stock.created_by = request.user
stock.portfolio_id = portfolio_id
stock.save()
return redirect('portfolio-overview')
else:
print("nope")
else:
print('else form statement')
form = StockForm()
context = {
'form':form
}
return render(request, 'portfolios/stock-add.html', context)
forms.py
class StockForm(ModelForm):
class Meta:
model = Stock
fields = ['quote', 'amount']
html
{% extends 'core/base.html' %}
{% block content %}
<div class="container">
<h1 class="title">Add Stock</h1>
<form method="POST" action=".">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="button is-primary">Submit</button>
</form>
</div>
{% endblock %}
models
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Portfolio(models.Model):
title = models.CharField(max_length=56)
description = models.TextField(blank=True, null=True, max_length=112)
created_by = models.ForeignKey(User, related_name='portfolios', on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name_plural = 'Portfolio'
def __str__(self):
return self.title
class Stock(models.Model):
Portfolio = models.ForeignKey(Portfolio, related_name='stocks', on_delete=models.CASCADE)
quote = models.CharField(max_length=10)
amount = models.IntegerField()
created_by = models.ForeignKey(User, related_name='stocks', on_delete=models.CASCADE)
created_at = models.DateField(auto_now_add=True)
def __str__(self):
return self.quote
If you look at the views.py file, when I submit the form, it won't even do print('request.method is ok')
I can add the stock via the admin page.
So I have no clew where to look anymore...
Cheers
When you post a form and need a special url (like your' with an attribute), i like to set action="{% url myview.views.stock_add portfolio_id %}"
action="." will save to the same page without taking care of extra parameters (if needed)
Just pass portfolio_id in the context and that will work
I found the answer, an InteregerField (from models.py) needs a default value.
Either default=None (or another value).
Cheers
I'm trying to add the ability to upload an image to a post but having issues.
The image field is in its own model but uses a foreign key to show which post it relates to.
At the moment the upload button does not post the form but also how would I use the post page url/slug/id as the image foreign key.
Would i need to call it in the html post page?
views.py
def designUpload(request):
if request.method == 'POST':
form = ImageForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return render(request, 'users/dashboard.html')
else:
form = ImageForm()
return render(request, 'users/dashboard.html', {
'form': form
})
**models.py**
class Designs(models.Model):
forbrief = models.ForeignKey(Brief, on_delete=CASCADE)
postedby = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
design = models.ImageField(null=True, blank=True)
date = models.DateTimeField(auto_now=True, blank=True)
forms.py
class ImageForm(forms.ModelForm):
class Meta:
model = Designs
fields = ["design",]
HTML Form
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<input type="image" name="mydesign">
<button type="submit">Upload</button>
</form>
I`m using Django 1.9 with the following:
views.py:
def a_new(request):
# submit button
if request.method == "POST":
form = AForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.save()
return redirect('ui:config-list')
# first visit
else:
form = AForm()
template = 'api/test_template.html'
context = RequestContext(request, {'form': form})
return render_to_response(template, context)
forms.py:
class AForm(forms.ModelForm):
b= forms.ModelMultipleChoiceField(
queryset=B.objects.all(),
widget=FilteredSelectMultiple("b", is_stacked=False)
)
class Meta:
model = A
fields = ('name', 'b', )
test_template.html
...
<form role="form" class="form-inline" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<div>
{{ form.name }}
{{ form.b }}
</div>
<div class="dl-horizontal">
<button type="submit" class="btn btn-success">Save</button>
</div>
</form>
models.py:
class A(models.Model):
name = models.CharField(max_length=100)
b = models.ManyToManyField(B, null=True, blank=True, name='b')
...
The problem is that when I use the Save button - only the name field is created in the item. The b item, that the widget is being used on, is just not being saved to the DB with the new item A created(it does show error if I leave the b field empty so I guess its checking it too).
What can be the problem?
See the documentation about using commit=False when you have a many-to-many field.
Note that there is no reason for you to be using commit=False here though. Remove it, and the second save, and Django will save your values directly.
b is ManyToManyField, it does on saved on the table A. In a different table the relation between A and B is maintained.
If you have an M2M field and do save(commit=False) you need to call this at the end:
form.save_m2m()
See the docs.
New to Django and Python and I need a little help with a foreign key drop down. Basically, I have a category model and a image model and I want users to be able to choose which category to put the image in. How do I create a drop down for the category in the image form? Are my views and html correct too? I have had a look online but I can't seem to do it myself. I keep getting errors.
Here are my models:
class Images(models.Model):
image = models.ImageField(upload_to='images', blank=False)
img_name = models.CharField(max_length=120, blank=True)
img_date = models.DateTimeField(default=now())
img_user = models.ForeignKey(User)
img_cat_id = models.ForeignKey(Categories)
def __unicode__(self):
return self.img_name
class Categories(models.Model):
cat_descr = models.CharField(max_length =120, blank=False)
def __unicode__(self):
return self.cat_descr
VIEWS:
#login_required
def upload_images(request):
context = RequestContext(request)
context_dict={}
if request.method == 'POST': # render the form, and throw it back.
# take the form data and process it!
form = UploadImagesForm(request.POST, request.FILES)
if form.is_valid():
print 'form is_valid'
upload_image = form.save(commit=False)
upload_image.img_user = request.user
if 'image' in request.FILES:
upload_image.image =request.FILES['image']
upload_image.save()
return render(request, 'rmb/upload.html', {'upload_image': form})
else:
print form.errors
# Not a HTTP POST, so we render our form using two ModelForm instances.
# These forms will be blank, ready for user input.
else:
form = UploadImagesForm()
context_dict = {'upload_image': form}
all_categories = Categories.objects.order_by('-id')
context_dict['all_categories'] = all_categories
print context_dict
return render_to_response('rmb/upload.html', context_dict, context)
FORMS:
class UploadImagesForm(forms.ModelForm):
#cat_list = ModelChoiceField(queryset=Categories.objects.all())
class Meta:
model = Images
fields=('image','img_name')
HTML:
{% block body_block %}
<form id="upload_form" method="post" action="/rmb/upload/"
enctype="multipart/form-data">
{% csrf_token %}
{{ upload_image.as_table }}
<input type="submit" name="submit" value="Upload" />
{% for categories in all_categories %}
<div> {{ categories.id }} </div>
{{ categories.cat_descr }}
<input type="submit" name="submit" value="Upload" />
{% endfor %}
</form>
{% endblock %}
You don't need to insert the HTML for the form manually, just use {{form}} in the template.
{% block body_block %}
<form id="upload_form" method="post" action="/rmb/upload/"
enctype="multipart/form-data">
{% csrf_token %}
{{ form }}
</form>
{% endblock %}
By default a ForeignKey will be a select field so you shouldn't need to do much else.
As an aside, give your models and fields more appropriate names. We know these are all image fields, because they are on the image and make sure, unless your model is a collection of things, you give it a singular name. Lastly, when using a Foreign Key and item gets an extra field of fieldname_id that is just the ID, whereas fieldname is the property that gives the related item as well.
So instead of:
class Images(models.Model):
image = models.ImageField(upload_to='images', blank=False)
img_name = models.CharField(max_length=120, blank=True)
img_date = models.DateTimeField(default=now())
img_user = models.ForeignKey(User)
img_cat_id = models.ForeignKey(Categories)
Use:
class Image(models.Model):
image = models.ImageField(upload_to='images', blank=False)
name = models.CharField(max_length=120, blank=True)
date = models.DateTimeField(default=now())
user = models.ForeignKey(User)
category = models.ForeignKey(Categories)