In my project, I am currently trying to access a manytomany field and compare it to another. I have several cases where I am doing something similar and it is working . The difference in this case is that I am trying to essentially say if one of the values in this many to many field equals a value in this other manytomanyfield, then do something....
Here is my code...
Book(models.Model):
publisher = models.ManyToManyField(Name)
Userprofile(models.Model):
publisher = models.ManyToManyField(Name)
In my Django template I am trying to do something like...
{% If user_publisher in form.initial.publisher_set.all %}
{{ publisher.name }}
{% endif %}
The example above is a simplified version of what I'm trying to do....I'm essentially trying to compare the manytomany fields and if any of the values match, perform an action. I've been at this most of today and have tried several combinations.
If I do something like
{% if user in form.initial.publisher.all %}
This works fine. I'm struggling to try and figure out how I can compare manytomanyfields. I suspect the user query works fine because it's not a manytomanyfield.
I'm thinking my format is off. I have tried to use the _set to publisher and the user publisher and when I go so far as to print the output, I am actually seeing that both the user_publisher and publisher querysets are the same. However, my django template is not showing me any results. Thanks in advance for any thoughts.
I have surfed SO all afternoon as well as Google, but can't quite figure out what I'm doing wrong.
Here is more detail to my issue. I am currently doing a CreateView whereby I am trying to get an existing record by overriding get_initial as shown below:
class BookUpdateView(CreateView):
model = Book
form_class = Book
template_name = 'Book/update_book.html'
def get_initial(self):
initial = super(BookUpdateView, self).get_initial()
book = Book.objects.get(pk=self.kwargs["pk"])
initial = book.__dict__.copy()
initial.update({
"publisher": publisher.all(),
})
return initial
Because I am copying in these records as a starting point and this is a CreateView, I don't yet have a PK or ID to query from a get_context_data perspective. Not sure how to go about getting the data that I am copying in but have not yet saved. I am actually trying to figure out if a user has the same publisher via their user profile and was able to figure out the format for get_context_data as shown below:
def get_context_data(self, **kwargs):
context = super(BookUpdateView, self).get_context_data(**kwargs)
user_publisher = self.request.user.userprofile.publisher.all()
return context
I tried to do something like....
{% if user_publisher in form.initial.publisher_set.all %}
But the template never recognizes that these two in fact do match...
When I print the variables....
They both show...
<QuerySet [<Publisher: ACME Publishing>]>
<QuerySet [<Publisher: ACME Publishing>]>
But the template does not recognize that they are the same. The screen is not rendered as I would expect when using the template language above. No errors, but end result isn't what I would expect either. Thanks in advance for any additional thoughts.
After a day or two of thinking about this, was able to figure out how to grab the PK and then use it in the context so that I could leverage the information via the context and not the form directly.
def get_context_data(self, **kwargs):
context = super(UpdateProcedureView, self).get_context_data(**kwargs)
pk=self.kwargs["pk"]
publisher = Publisher.objects.filter(pk=pk).filter(individual_access=self.request.user).count()
return context
Then in the form I can say something like if publisher > 0 then do something fancy. Thanks for the suggestions along the way to help me think this through.
Related
In my django website, I have 3 classes: Thing, Category and SubCategory.
Thing has 2 ForeignKeys: "Category" and "SubCategory" (such as Car and Ferrari).
SubCategory has 1 ForeighKey: "Category" (Ferrari is in the category Car)
When I create an instance of Thing in the Admin part and when I choose a Category, I would like that the "SubCategory" field only shows the SubCategories linked to the Category I chose. Is that possible?
I saw the possibility to change the AdminForm like:
class ThingFormAdmin(forms.ModelForm):
def __init__(self,Category,*args,**kwargs):
super (ThingFormAdmin,self ).__init__(*args,**kwargs) # populates the post
self.fields['sub_category'].queryset = SubCategory.objects.filter(category= ... )
But I don't know what to write on the ...
Thanks for the help!
in general always this solution would work:
you need some javascript to catch what has been selected for first selection. then do filtering agin using javascript.
but in django admin, there is autocomplete_fields available. using this would create a kind of selection-input that uses ajax to do some magic filtering on choices when user types some characters. it uses the get_search_results method of the related models admin.ModelAdmin class. overriding that method and giving some extra data to that method could help. but it's the longest way to walk.
Thanks! I will look in the 1st answer after the 2nd, because the fact that I don't have to write JS is very nice, as I am very bad in it.
I manage to use the autocomplete_field to work, but I am stuck with the redefinition of the get_search_results method. If I understood correctly the doc, it will be something like:
def get_search_results(self, request, queryset, search_term):
queryset, use_distinct = super().get_search_results(request, queryset, search_term)
try:
cat = search_term
except ValueError:
queryset |= self.model.objects.all()
else:
queryset |= self.model.objects.filter(category=cat)
return queryset, use_distinct
But I don't understand from where this search_term comes from, and how I can specify it. Any ideas?
https://simpleisbetterthancomplex.com/tutorial/2018/01/29/how-to-implement-dependent-or-chained-dropdown-list-with-django.html
This tutorial will walk you through every step of doing whatever I presume you need to do.
I am trying to query a table where I have many records with the same name, on purpose. In my example, I'm using the make of the car, and unfortunately I've already ruled out using a foreignkey. Long story. Anyway, I've been able to determine that I can query the table using a ModelChoiceField and using the distinct command as I'm using Postgresql as shown below:
class Vehicle(forms.Form):
dropdown = forms.ModelChoiceField(queryset=Car.objects.none())
def __init__(self, *args, **kwargs):
super(Vehicle, self).__init__(*args, **kwargs)
self.fields['dropdown'].empty_label = ''
qs = Car.objects.distinct('vehicle_make')
The code above does what I need related to the dropdown, it limits the ModelChoiceField to just the unique values of the vehicle_make of the car.
The challenge is when I go to try to display all of the records with that vehicle_make in my template. I've tried to do a Detail View, but it is only showing me that individual record. That make sense since detail view is just for that record, but I'm trying to figure out how to query the table to show me all of the records with that vehicle_make. I've explored the ChoiceField as well, but can't seem to get this to work either. I've tried several variations of the code below in the template, but nothing seems to work.
{% for vehicle_make in car.queryset %}
{{ vehicle_make }}
{% endfor %}
My model is as follows:
Car(models.Model):
vehicle_make = models.Charfield(max_length=264,unique=False)
def __str__(self):
return self.vehicle_make
Thanks in advance for your input and suggestions.
You can query for all Car objects with a given value for vehicle_make with Car.objects.filter(vehicle_make = 'foo'). For example, this ListView would list all cars:
from django.views.generic.list import ListView
from .models import Car
class CarListView(ListView):
context_object_name = "car_list"
queryset = Car.objects.all()
Whereas this view would list all cars of make 'foo':
class FooCarListView(ListView):
context_object_name = "car_list"
queryset = Car.objects.filter(vehicle_make = 'foo')
One easy way to make this more "dynamic" would be to look for a search query in the url, either as a keyword argument or as a querystring. You could use your existing form to create a URL like this, then parse it in a view. For instance, this view would look for URLs appended with ?search=bar:
class SearchableCarListView(ListView):
context_object_name = "car_list"
def get_queryset(self):
search_term = self.request.GET.get('search', None)
if search_term is not None:
return Car.objects.filter(vehicle_make = search_term)
return Car.objects.all()
Your use case may be better served by using an icontains or iexact lookup, or even by making use of Django's full text search.
In the template for any of these views, you can access all of the Car objects in your queryset like so:
{% for car in car_list %}
{{car}}
{% endfor %}
I hope that I have understood and addressed your question. I am not 100% sure how you are using your form right now, so please let me know if I have overlooked anything there.
After our discussion in the comments, I think you are overcomplicating things with your form, and I think that your lookup might not be doing what you want.
We will get a ValuesQuerySet of all distinct vehicle_make values:
qs = Car.objects.values('vehicle_make').distinct()
(See: Select DISTINCT individual columns in django?)
This returns a ValuesQuerySet that looks like this:
<QuerySet [{'vehicle_make': 'vehicle_make_1'}, {'vehicle_make': 'vehicle_make_2'}...]
Where vehicle_make_1, vehicle_make_2 etc. are your distinct values.
We can give this queryset qs to our template and construct a select element. We could also simplify it first to a list of values to make it easier to work with in the template:
values_list = [ c['vehicle_make'] for c in qs.all() ]
Pass that value to our template and use it to make our select element:
<select name='search'>
{% for vehicle_make in values_list %}
<option value = {{vehicle_make}} > {{vehicle_make}} </option>
{% endfor %}
</select>
From here you have several options. In my opinion, the simplest thing would be using this select element in a form that uses the GET method to construct a search URL like we discussed earlier. Check out the first answer to this question for more info: <form method="link" > or <a>? What's the difference? There is a code snippet in the first answer to that question that can easily be adapted to create a GET-based search form with your newly-created select element.
All,
I'm new to Django and have been doing pretty good so far but this one has me stumped. I'm trying to utilize ModelChoiceField for a number of records that have the same name. I'm using Postgresql so I was able to determine that I need to use the distinct command and that is working perfectly. The records in my dropdown are all stripped down to just one version of each of the records. However, when I try to get all of the versions of a particular record, that's where I'm getting lost. I am able to get the detail of each record if I don't use distinct via a DetailView, but I am really trying to get all versions of each record on the screen after the modelchoicefield.
Here is my form:
class History(forms.Form):
dropdown = forms.ModelChoiceField(queryset=History.objects.all())
def __init__(self, user, *args, **kwargs):
super(History, self).__init__(*args, **kwargs)
self.fields['dropdown'].widget.attrs['class'] = 'choices1'
self.fields['dropdown'].empty_label = ''
qs = History.objects.all().distinct('record_name')
self.fields['dropdown'].queryset = qs
I am ultimately trying to get a view the queryset on the screen via my template. I have tried several different versions of code in the template but nothing seems to work. If I use the CBV DetailView without distinct I can get all of the records with their detail view fine. However, that's not what I'm trying to do. I have played with several versions of the queryset command in the template as I found several questions similar to mine but can't seem to get it to work. I found a couple of references to something similar to:
{% for record in form.history.field.queryset %}
etc.
{% endfor %}
But can't seem to get it to work in my Django template. Any and all help is appreciated! Thank you in advance!
In this case I'd either suggest
a) to put the value of your dropdown field into your url matching. See the django docs for named groups in URL. Additionally, you could add an onchange event to your dropdown-field which redirects to <current url>/<value of dropdown> or simply change the value of (if existing) buttons which links to the following page. Caution: With this solution you must ensure that the values of your dropdown field matches url-format (django's slugify might be useful for this).
or
b) to add your dropdown field to your input form or as input field. Then you can extract the value of your dropdown with:
try:
dropdown_value = request.POST['dropdown-field-name'] # dict-error if field is not in request.POST
except:
# some error actions
then you can add this value as filter to your queryset:
def get_queryset(self, dropdown_value=None):
# ...
qs = qs.filter('field-name' = dropdown_value) # possibly no/wrong results if dropdown_value is corrupted or manipulated
I am retrieving a bunch of things with a queryset and displaying them as a list, that is then clickable to view the chosen article's details.
So in the article's details view, I have a is_creator method:
#login_required
def is_creator(userProfile, article):
if userProfile == article.creator:
return True
else:
return False
So I can display an edit button at will.
On the homepage though, it's a different story because I'm making a query, and giving the queryset directly to the template that will make a for loop to display the titles. I still want to know for each article if the current user is the creator though.
So I'm thinking of adding the work in the model itself, not to have to duplicate code anywhere.
#property
def is_creator(self,user):
if self.creator.user == user:
return 1
else:
return 0
I was thinking that by adding that in the model, I should be able to call in the template {% if event.is_creator user %}test{% endif %} pretty easily. Seems that I'm wrong, because I'm facing:
TemplateSyntaxError at /
Unused 'user' at end of if expression.
I'm coming from the PHP world so it feels like this should work, but I'm obviously doing something wrong.
Thanks in advance :)
EDIT: I'm guessing that another solution would be in the view to loop through the Queryset with something like:
variables['articles'] = Event.objects.filter(
(Q(creator=me) | Q(bringing__attendee=me)) & Q(date_start__lt=datenow) & Q(date_end__gt=datenow)
).order_by('-date_start')
for article in variables['articles']:
article.iscreator=1 (I can do some more work here)
But it seems like having to loop over the QS is not the best idea.
It is very sad but you cant pass params to methods from templates(indeed this is a good idea - so you don't mix presentation logic with model logic, almost :) ). You have to write a template tag for this purpose.
https://docs.djangoproject.com/en/dev/howto/custom-template-tags/
tag would look like this(not tested):
#register.simple_tag(takes_context=True) # assuming you are running in request context
def current_user_is_creator(context,article):
user = context['request'].user
return article.creator.user == user # dont forget to add proper checks
Or you could prepare required data in the view.
After stripping down my code to the minimum, it still does not work. I alway get the hint:
(Hidden field id) Select a valid choice. That choice is not one of the available choices.
This is what my forms looks like:
class ChangeItemForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(ChangeItemForm, self).__init__(*args, **kwargs)
for key in self.fields:
self.fields[key].required = False
class Meta:
model = Item
fields = ('name','tags','no')
ChangeItemFormset=modelformset_factory(Item,extra=0,form=ChangeItemForm)
and my view looks like this:
def manage_view(request):
if request.method=='POST':
itemforms=ChangeItemFormset(request.POST,
queryset=Item.objects.filter(creator=request.user))
else:
itemforms=ChangeItemFormset(queryset=Item.objects.filter(creator=request.user))
messages.info(request,str(itemforms.is_valid())) #always prints False
context=RequestContext(request)
context.update({'formset':itemforms,
})
return render_to_response('sonitem/test_forms.html',context)
and in my template i do this:
<form action="." method="post" name="upload_image">
<button type="submit" name="action" value="change">change</button>
{%for form in formset.forms%}
{{form}}
{%endfor%}
{{formset.management_form}}
{%csrf_token%}
</form>
messages:
{%for message in messages%}
<div>{{message}}</div>
{%endfor%}
Thats it. I don't have a clue where to look further. Maybe i do it all wrong? At least i am sure i somehow missed an important piece of how formsets work... if someone could please help me out.
edit:
looks like it's somehow related to my model Item. Just made a new, simplified model, Item2, and this code worked exactly as it should. Item2 had just the fields that are in the form above. Back to Item: Why (and more important - how) can modelfields that are not in the formset affect the formset validation?
The Item2 model, the one that is working:
class Item2(models.Model):
name=models.CharField(max_length=50)
tags=TagField()
no=models.IntegerField(blank=True,null=True)
creator = models.ForeignKey(User, related_name='creator')
edit2:
I think i have encircled what causes the trouble: i have defined a model manager as default, that is looking for a status - which is a models.IntegerField. As soon as i put this into the class, it stops working and delivers exactly the error message from above.
The Item model looks somewhat like this:
class Item(models.Model):
PRIVATE_STATUS=1
PUBLIC_STATUS=2
RELEASED_STATUS=3
STATUS_CHOICES=((PRIVATE_STATUS ,'private'),
(PUBLIC_STATUS ,'public' ),
(RELEASED_STATUS,'released'))
status = models.IntegerField(choices=STATUS_CHOICES,default=PRIVATE_STATUS)
public = PublicItemManager()
objects = models.Manager()
name=models.CharField(max_length=50)
tags=TagField()
no=models.IntegerField(blank=True,null=True)
file=models.FileField()
creator = models.ForeignKey(User, related_name='creator')
status=models.IntegerField(blank=True,null=True)
So i have to extend my question above. Is it possible to use the status (which definitely is a required field) in the model and still use a formset? The formset is only for editing, not for creating the items. And it is always prepopulated, there is no chance there will be an empty status-field.
I still don't understand how a field that is not even in the form can impede the validation of it. And, by the way, if i am using just the ChangeItemForm, it does not.
edit 3:
here is the manager, stripped down to the most simple version causing trouble:
class PublicItemManager(models.Manager):
def get_query_set(self):
return super(PublicItemManager,
self).get_query_set().filter(status=self.model.PUBLIC_STATUS)
when i
#public=PublicItemManager
everything runs smooth.
edit 4:
oh, and by the way: Why is the public manager affecting any validation, when i have the queryset working with the objects manager?
queryset=Item.**objects**.filter(creator=request.user)
After studying the django-docs for quite a while i was able to find the solution. Looks like in certain situations django creates "automatic" managers that are not the _default_manager. Docs are here: http://docs.djangoproject.com/en/1.2/topics/db/managers/#controlling-automatic-manager-types
And here is the code for the working Manager:
class PublicItemManager(models.Manager):
#this is the important line:
use_for_related_fields = True
def get_query_set(self):
return super(PublicItemManager,self).get_query_set().filter(status=self.model.PUBLIC_STATUS)