Django choice field default value and readonly - django

I try to set my field in form readonly and put any default value.
This is a part of my form:
category = forms.CharField(widget=forms.TextInput(attrs={'readonly':
'readonly'}),
initial=Category.objects.get(name='Zdrowie i uroda'))
class Meta:
model = Site
fields = ('url', 'name', 'description', 'keywords', 'group', 'category',
'subcategory', 'category1', 'subcategory1')
I get an error: Cannot assign "'Zdrowie i uroda'": "Site.category" must be a "Category" instance.
This is my site model:
class Site(models.Model):
category = models.ForeignKey('Category')
subcategory = ChainedForeignKey(
'SubCategory',
chained_field='category',
chained_model_field='category',
show_all=False,
auto_choose=True)
name = models.CharField(max_length=70)
description = models.TextField()
# importuje zmienione TextFields widgets.py
keywords = MyTextField()
date = models.DateTimeField(default=datetime.now, editable=False)
url = models.URLField()
is_active = models.BooleanField(default=False)
category1 = models.ForeignKey('Category', related_name='category', blank=True, null=True, default=None)
subcategory1 = ChainedForeignKey(
'SubCategory',
chained_field='category1',
chained_model_field='category',
related_name='subcategory',
show_all=False,
auto_choose=True, blank=True, null=True, default=None)
group = models.CharField(max_length=10, choices=(('podstawowy', 'podstawowy'),
('premium', 'premium')), default='podstawowy')
def get_absolute_url(self):
return reverse('site', args=[str(self.category.slug),
str(self.subcategory.slug), str(self.id)])
def get_thumb(self):
host = urlparse(self.url).hostname
if host.startswith('www.'):
host = host[4:]
thumb = 'http://free4.pagepeeker.com/v2/thumbs.php?size=s&url=' + host
return thumb
class Meta:
verbose_name_plural = "Strony"
def __str__(self):
return self.name
I can't deal with it. Any clues?
Finally I excluded category, subcategory fields from my model.form and added it to html source manually:
{{ form_extended|bootstrap }}
<label for="example-text-input" class="col-2 col-form-label">Category</label>
<input class="form-control form-control-lg" type="text" name="category" disabled required value="{{ form_extended.initial.category.name }} " />
<label for="example-text-input" class="col-2 col-form-label">Subcategory</label>
<input class="form-control form-control-lg" type="text" name="subcategory" disabled required value="{{ form_extended.initial.subcategory.name }} " />
I don't think it is a right way but I can't put some data to form initial values. Should I create my form manually from scratch? My way isn't good because I use jQuery to extend form. Now category, subcategory fields are las but they shouldn't (when user choose "premium" group from choice fields, after subcategory field there should appear "category1", "subcategory1" fields...
As always - I am sorry for my terrible English. Every post is like exam to me.

Options without further delving into Django forms:
Change Model Field
This might not be an option, but you could try setting:
class Site(models.Model):
category = models.ForeignKey('Category', editable=False)
Remove the explicit declaration of the category form field from your form and simply set the initial category when initializing the form or override __init__ to set it.
Change Form Field
Django would normally render a ForeignKeyField as drop down. Do you explicitly want a text input instead? In that case you have to handle data validation and the data mapping yourself.
A way of working around that would be to remove the explicit declaration of the form field and simply handle this field separatly in your HTML template:
<input type="text" name="category" value="{{ form.initial.category.name }}" />
"Do you explicitly want a text input instead?" - No.
In that case, you want a ModelChoiceField instead of a CharField.
category = forms.ModelChoiceField(
queryset=Category.objects,
empty_label=None,
disabled=True, # Django 1.9+
initial=Category.objects.get(name='Zdrowie i uroda'))

Related

Filtering data using age group in django

I want to filter my products based on for what age group they are intended to. My plan of doing that is using a boolean field and filter the products by that. I have a dropdown menu which lists the different age groups and when a person clicks on one, a page will be displayed with the products which have boolean true for that age group.
Here is my models.
class Product(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
title = models.CharField(max_length=150)
image = models.ImageField(null=False, upload_to='images/')
price = models.DecimalField(max_digits=12, decimal_places=2, default=0)
amount = models.IntegerField(default=0)
detail = RichTextUploadingField()
create_at = models.DateTimeField(auto_now_add=True)
update_at = models.DateTimeField(auto_now=True)
child = models.BooleanField(default=False)
teen = models.BooleanField(default=False)
adult = models.BooleanField(default=False)
def __str__(self):
return self.title
Is this the way I should do it? If it is the case should I use 3 different views.py for each boolean or is there any efficient way?
Thank you in advance!
No, you don't need 3 views to show this. You can get the value user submits via a form like this request.GET if you didn't specify any method attribute in the form or for POST request you can get the data using request.POST.
Assuming you are using pure Django with functional-based views. Then your view will look like this.
def get_products(request):
# getting the gender group you passed via form
gender_group = request.GET.get("gender_group")
# assuming you are passing `child`, `teen` and `adult` through from drop-down value
user_products = Products.objects.filter(**{gender_group: True})
return render(request, "you_template_name.html", {"products": user_products})
Assuming you html form will be something like this one.
<form method="get">
<!-- you other fields -->
<select name="gender_group">
<option value="child">Child</option>
<option value="teen">Teen</option>
<option value="adult">Adult</option>
</select>
</form>
#Mubashar javed you are correct. I just added two things and it worked.
<Form action="{% url 'get_products' %}" method="get">
<select name="gender_group">
<option value="child">Child</option>
<option value="teen">Teenager</option>
<option value="adult">Adult</option>
<input type="submit" value="Submit">
</select>
</Form>

Django forms - Allow a user to create a group for other users

I am trying to let a user create a "club" (basically a group) where the user later on can add users to.
Currently it does not create a field in the database somehow.
Any suggestions would be appreciated since I am fairly new to forms.
Model
class Club(models.Model):
owner = models.CharField(max_length=30)
topic = models.CharField(max_length=30)
start = models.DateTimeField(verbose_name='start date', auto_now_add=False)
end = models.DateTimeField(verbose_name='end date', auto_now_add=False)
account = models.ManyToManyField(Account)
Views
#login_required
def add_club(request):
if request.method == "POST":
form = AddClubForm(request.POST, instance=request.user)
print(form)
if form.is_valid():
form.save()
return HttpResponseRedirect(request.path_info)
else:
form = AddClubForm(instance=request.user)
return render(request, 'page/club.html', {
"form": form,
})
Form
class AddClubForm(forms.Model):
owner = forms.CharField(required=True)
topic = forms.CharField(required=False)
start = forms.DateField(required=False)
end = forms.DateField(required=False)
class Meta:
model = Club
fields = (
'owner',
'topic',
'start',
'end',
)
Template
<form method="POST" action="">
{% csrf_token %}
<div class="col-md-6">
<label class="labels">Create a club</label>
{{ form.owner }}
<input class="btn" type="submit" value="Add club">
</div>
</form>
Since this answered your problem, I am posting the solution here:
You need to add blank=True, null=True to your fields in your model, otherwise it expects them when saving the form.
class Club(models.Model):
owner = models.CharField(max_length=30)
topic = models.CharField(max_length=30, blank=True, null=True)
start = models.DateTimeField(verbose_name='start date', auto_now_add=False, blank=True, null=True)
end = models.DateTimeField(verbose_name='end date', auto_now_add=False, blank=True, null=True)
account = models.ManyToManyField(Account, blank=True)
Concerning the instance=request.user, I believe you misunderstanding the use of instance in a ModelForm.
If the request method is GET, the instance is used to populate a ModelForm with data from an existing Club object, and then pass it to your template to display the information.
If the request method is POST (or PUT), instance represent the existing Club object you want to update with data received from the form.
You usually need to use the instance arg in a DetailView (either to update or retrieve one specific Club), never when creating an object.
That's why you need to remove the instance arg in your views.py:
form = AddClubForm(request.POST)

Django - dynamic change form fields

I have a simple form to add a website to database. This is my site model:
class Site(models.Model):
category = models.ForeignKey('Category')
category1 = models.ForeignKey('Category', related_name='+',)
subcategory = ChainedForeignKey(
'Subcategory',
chained_field='category',
chained_model_field='category',
show_all=False,
auto_choose=True)
name = models.CharField(max_length=70)
description = models.TextField()
# importuje zmienione TextFields widgets.py
keywords = MyTextField()
date = models.DateTimeField(default=datetime.now, editable=False)
url = models.URLField()
is_active = models.BooleanField(default=False)
group = models.CharField(max_length=2, choices=(('Basic',
'Basic'), ('Premium', 'Premium')))
subcategory1 = ChainedForeignKey(
'Subcategory',
chained_field='category1',
chained_model_field='category1',
related_name='subcategory1',
show_all=False,
auto_choose=True)
def get_absolute_url(self):
return "%s/%i" % (self.subcategory.slug, self.id)
class Meta:
verbose_name_plural = "Sites"
def __str__(self):
return self.name
Forms.py
class SiteAddFormFull(forms.ModelForm):
url = forms.URLField(widget=forms.TextInput(attrs={'readonly': 'readonly'}))
class Meta:
model = Site
fields = ('url', 'name', 'description', 'keywords', 'group', 'category1','subcategory1')
I would like to change my form by adding fields 'Category1', 'Subcategory1' after user choose value in group field ('Premium'). Form should reload itself and show those fields. Before choosing 'Premium' fields 'Category1', 'Subcategory1' should be invisible. How can I achieve that?
In my forms.py I added:
widgets = {'category1': forms.HiddenInput(), 'subcategory1':
forms.HiddenInput()}
In my .js file I try to show those fields but it doesn't work:
$(":hidden").show();
// $("#id_category1".show() and other posibilities
In my page soure I have
<input id="id_category1" name="category1" type="hidden" /><input id="id_subcategory1" name="subcategory1" type="hidden" />
Why it doesn't work?
You don't need HiddenInput for categories. Just hide it with jquery and show it on select change event.
<select id="group">
<option value="First">First</option>
<option value="Premium">Premium</option>
<option value="Second">second</option>
</select>
<select id="category1">
<option value="First">First</option>
<option value="Second">second</option>
</select>
Jquery
$(document).ready(function(){
$('#category1').hide();
$('#group').change(function(e) {
var group = $(this).val();
if (group == 'Premium'){
$('#category1').show();
} else {
$('#category1').hide();
}
});
});
https://jsfiddle.net/fwfm9byy/1/

Django - how to exclude repeating objects

models.py
class Location(models.Model):
name = models.CharField(max_length=100, verbose_name=u"Локация", default=u'')
country = models.CharField(max_length=100, verbose_name=u"Страна", default=u'')
class Country(models.Model):
name = models.CharField(max_length=50, verbose_name=u"Страна")
class Photo(models.Model):
location = models.ForeignKey(Location, null=True, verbose_name=u'Фото')
photo = models.ImageField(upload_to='photos', null=True)
forms.py
class LocationForm(forms.ModelForm):
class Meta:
model = Location
fields = ['name', 'country']
photos = MultiFileField(min_num=1, max_num=10)
def save(self, commit=True):
instance = super(LocationForm, self).save(commit)
for each in self.cleaned_data['photos']:
Photo.objects.create(photo=each, location=instance)
return instance
views.py
class AddLocationPageView(CreateView):
model = Location
form_class = LocationForm
template_name = 'add_location.html'
class BrowseLocationsPageView(ListView):
model = Country
context_object_name = 'countries'
template_name = "browse_locations.html"
add_location.html
<form action="" method="POST">{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-default" type="submit">Add</button>
</form>
browse_locations.html
{% for country in countries %}
{{ country }}
{% endfor %}
I need to get in browse_locations.html the list of countries without repeating.
For exapmple, I am creating location object with country 'USA'. Then I am creating second one with country 'USA'. And in my view I can see the list where there are two 'USA', but I need only one.
Thanks!!!
If you are using postgres, then you can use the distinct queryset filter with a field name.
class BrowseLocationsPageView(ListView):
def get_queryset(self):
return self.model.objects.distinct('name')
This solves the "issue" but there is a bigger problem at hand. Wherever you are creating the countries, you are creating new countries instead of looking if there is an existing country with the same name - get_or_create may be useful here.
Location should probably have a foreign key to a country too...
You have country as a CharField in the Location Model. Hence the repitition.
Change the country field as a ForeignKey in the Location model

Django1.6 UpdateView, how to display field without update it

models.py
class Application(models.Model):
desc = models.CharField(max_length=40, unique=True, null=False)
name = models.CharField(max_length=40, null=False)
user = models.ForeignKey(User)
views.py
class ApplicationUpdate(UpdateView):
model = Application
template_name = "apps/update.html"
fields = ['name', 'desc']
context_object_name = "app"
success_url = reverse_lazy('app-list')
templates
<div class='update-item'>
{{form.name.error}}
{{form.name.label_tag}}
{{form.name}}
</div>
<div class='update-item'>
{{form.desc.value}}
</div>
Here I want to display desc field in template, but only POST name field when update it. Any solution for it?
Try one of these:
Set readonly attributes on fields that you don't want to be changed.
Instead of {{form.desc.value}} you can display instance field value - {{ form.instance.desc }}, next remove desc field from include attribute.