Django Form Models and Editing - django

Wow, I'm having such a hard time on this. I must be doing something wrong, I'm getting an incredible ammount of queries.
So, my models are the following:
Player
Clan
Match (as in game match)
MatchMap (the maps played of a match)
MatchPlayer (the players of a match)
All of them are related via foreign key, no m2m relationship. A player can be in a clan and a match involves 2 clans. A match can have any ammount of maps and only players from the two clans involved can be in the match (although on the future the players might not be in the same clan they played on that match, so I specify the side they played on the match).
So, I made the submit match, all ok. But to edit this info, it's caos!
For editing MatchPlayers of a match I tried using inlineformset_factory
PlayersFormSet = inlineformset_factory(MatchBetweenClans, MatchPlayer)
playersForms = PlayersFormSet(instance=match)
This already starts bad because for each instance of player on a match, Django hits the database and gets a list of all players. If for example 6 players are on a match, and I have 2 empty forms provived by the inlineformset_factory, I see on the log
SELECT
...
FROM
`accounts_customuser`
8 times.
Now, even if that worked correctly for me, it does not do what I need. When adding players to a match, not all players should be on the list, only those from the 2 specified clans, ideally as the form of checkboxes (each checkbox being a player of a clan). When submitting the match this is easy to do:
clan1PlayerList = CustomUser.objects.filter(clan=clan1Instance)
clan2PlayerList = CustomUser.objects.filter(clan=clan2Instance)
playersClan1 = forms.ModelMultipleChoiceField(queryset=clan1PlayerList, label="Jogadores - "+clan1Instance.tag+"", widget=forms.CheckboxSelectMultiple(attrs={'class':'input_checkbox'}))
playersClan2 = forms.ModelMultipleChoiceField(queryset=clan2PlayerList, label="Jogadores - "+clan2Instance.tag, widget=forms.CheckboxSelectMultiple(attrs={'class':'input_checkbox'}))
Is there anyway I could have this on a formulary to be edited? I can't find a way to send the playerlist of a clan and the currect players of a match to a form.
Thanks

You might want to look at select_related.
Here are the docs.
I had to go read your question again, as the question part of it wasn't clear to me. I thought you had a problem of too many queries hitting the database (which may be a problem too and select related will help there), but your question really is:
How to filter a form field to only allow values based on a different field?
Correct? From your question:
When adding players to a match, not all players should be on the list, only those from the 2 specified clans, ideally as the form of checkboxes (each checkbox being a player of a clan).
In your view, filter the fields on each form by clan. Something like (without your models I can only guess at field names):
form.fields['player'].queryset=form.fields['player'].queryset.filter(clan__in=list_of_selected_clans)
Unrelated suggestion: look at python's string interpolation.
Boa sorte!

Related

Filter multiple Django model fields with variable number of arguments

I'm implementing search functionality with an option of looking for a record by matching multiple tables and multiple fields in these tables.
Say I want to find a Customer by his/her first or last name, or by ID of placed Order which is stored in different model than Customer.
The easy scenario which I already implemented is that a user only types single word into search field, I then use Django Q to query Order model using direct field reference or related_query_name reference like:
result = Order.objects.filter(
Q(customer__first_name__icontains=user_input)
|Q(customer__last_name__icontains=user_input)
|Q(order_id__icontains=user_input)
).distinct()
Piece of a cake, no problems at all.
But what if user wants to narrow the search and types multiple words into search field.
Example: user has typed Bruce and got a whole lot of records back as a result of search.
Now he/she wants to be more specific and adds customer's last name to search.So the search becomes Bruce Wayne, after splitting this into separate parts I'm having Bruce and Wayne. Obviously I don't want to search Orders model because order_id is a single-word instance and it's sufficient to find customer at once so for this case I'm dropping it out of query at all.
Now I'm trying to match customer by both first AND last name, I also want to handle the scenario where the order of provided data is random, to properly handle Bruce Wayne and Wayne Bruce, meaning I still have customers full name but the position of first and last name aren't fixed.
And this is the question I'm looking answer for: how to build query that will search multiple fields of model not knowing which of search words belongs to which table.
I'm guessing the solution is trivial and there's for sure an elegant way to create such a dynamic query, but I can't think of a way how.
You can dynamically OR a variable number of Q objects together to achieve your desired search. The approach below makes it trivial to add or remove fields you want to include in the search.
from functools import reduce
from operator import or_
fields = (
'customer__first_name__icontains',
'customer__last_name__icontains',
'order_id__icontains'
)
parts = []
terms = ["Bruce", "Wayne"] # produce this from your search input field
for term in terms:
for field in fields:
parts.append(Q(**{field: term}))
query = reduce(or_, parts)
result = Order.objects.filter(query).distinct()
The use of reduce combines the Q objects by ORing them together. Credit to that part of the answer goes to this answer.
The solution I came up with is rather complex, but it works exactly the way I wanted to handle this problem:
search_keys = user_input.split()
if len(search_keys) > 1:
first_name_set = set()
last_name_set = set()
for key in search_keys:
first_name_set.add(Q(customer__first_name__icontains=key))
last_name_set.add(Q(customer__last_name__icontains=key))
query = reduce(and_, [reduce(or_, first_name_set), reduce(or_, last_name_set)])
else:
search_fields = [
Q(customer__first_name__icontains=user_input),
Q(customer__last_name__icontains=user_input),
Q(order_id__icontains=user_input),
]
query = reduce(or_, search_fields)
result = Order.objects.filter(query).distinct()

Django store the original value of a field

I am a newbie with Django trying to create a dashboard application reporting on some key milestone dates. I want to be able to track how the key dates are changing. For example:If the kick off date has been changed 5 times I want to be able to report 1. the first date entered, 2. Current date, 3. The date before the last update.
Thank you
Your question is not clear. But for the logic you have asked one thing we can do is to make a model in which the edited dates and user will be fields. Use user as foreign key of your User model. I will just give an example model.
class Dates(models.Model):
event = models.ForeignKey(Event)
date = models.DateField()
This is a very basic method which i am saying. This is a bit complex and you will have to check if the field has changed five times and all.
For a better answer please make the question clear.

how to match a field name with another field name

I have two fields that run throughout a website that I would like to match so that when a user inputs a value either of the fields, it will match the other field. I'm using Sitecore Rocks and am trying to use a query to do this.
select ##h1#, ##Title#
from /sitecore/Content/Home//*[##h1# !="##Title#"];
update set ##h1# = ##Title# from /sitecore/Content/Home//*[##Title# = "<id>"];
What am I missing here?
This article talks about tapping in to the item:saving event which allows you to compare the fields values of the item before and after the changes:
http://www.sitecore.net/Community/Technical-Blogs/John-West-Sitecore-Blog/Posts/2010/11/Intercepting-Item-Updates-with-Sitecore.aspx
Using this, you can determine which field has been amended, then change the other to match.
I've had to do something similar to this when a new field was added, and we wanted to set the initial value equal to an existing field. It may be a bug in Sitecore Rocks, but I found it would only update a field when a static value was part of the query.
When I ran ##h1# = ##Title#, the query analyzer would return the correct number of items updated, but no values were actually updated. However, ##h1# = '<id>' worked perfectly. After trying a number of things, I found this did what I wanted.
update set ##h1# = '' + ##Title# from /sitecore/Content/Home//*[##Title# = "<id>"];
I hope that helps.

How to create linked (associated) automatically updated form fields in GAE Django

I am new to Django and GAE. I would like to create two input fields, where the first one is a drop-down menu (let name it select), which decides the values in the second one (let name it val).
For example, once 'A' is chosen from 'select', field 'val' will show '1'. similarly, 'B' is associated to '10'. I have written several lines below, but it does not work. Two issues:
The second field ('val') always equals 0.
It seems like my second field ('val') does not 'listen' to the choice made by the first one ('select'), which means those two fields are not linked.
Can anyone give me some suggestions (or recommend books on using Django on GAE)? Thank you!
select_CHOICES=(('A','A'),('B','B'),('Other','Other'))
select = forms.ChoiceField(choices=select_CHOICES, initial='A')
def get_choices(select):
if select=='A':
r= 1
elif select=='B':
r= 10
else:
r= 0
return r
val=forms.FloatField(initial=get_choices(select))
I think you have understood how django works a bit wrong. The code that you input is run before the page is rendered, so no selection is made yet. If you want the input field to dynamically change as user makes the choise on page, you should use Javascript.
Also you are comparing a Field (select) to a string ('A'), which naturally always is unequal.
Read more documentation and tutorials and you'll soon get how it works.

Django admin: Inline of a Many2Many model with 2 foreign keys

after wracking my brain for days, I just hope someone can point me to the right approach.
I have 4 Models: Page, Element, Style and Post.
Here is my simplyfied models.py/admin.py excerpt: http://pastebin.com/uSHrG0p2
In 2 sentences:
A Element references 1 Style and 1 Post (2 FKs).
A Page can reference many Elements, Elements can be referenced by many pages (M2M).
On the admin site for Page instances I included the M2M relation as 'inline'. So that I have multiple rows to select Element-instances.
One row looking like: [My Post A with My Style X][V]
What I want is to replace that one dropdown with 2 dropdowns. One with all instances of Post and one with all instances of Style (creating Element instances in-place). So that one row would look similar to the Element admin site: [My Post A][V] [My Style X][V]
Sounds easy, but I'm just completely lost after reading and experimenting for 2 days with ModelForms, ModelAdmins, Formsets, ... .
Can I do that without custom views/forms within the Django admin functionality?
One of my approaches was to access the Post/Style instances from a PageAdminForm like this, trying to create a form widget manually from it... but failed to do so:
p = Page.objects.get(pk=1)
f = PageAdminForm(instance=p)
f.base_fields['elements'].choices.queryset[0].post
Any advice or hint which way I need to go?
Thank you for your time!
I got exactly what I wanted after removing the M2M field and linking Elements to a Page with a 3rd ForeignKey in Element:
class Element(models.Model):
page = models.ForeignKey(Page)
post = models.ForeignKey(Post)
style = models.ForeignKey(Style)
Actually a non-M2M link makes more sense for my application after all.
Memo to self: Rethink model relations before trying to outsmart Django :-(